blob: 334d99b38b13318d0d1ecda319e97c3a41d9ec59 [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 };
Stefan Berger0d289b52015-06-09 19:56:29 -040036static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
37static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040038
39static const u8 CommandFlag_FALSE[1] = { 0x00 };
40static const u8 CommandFlag_TRUE[1] = { 0x01 };
41
Stefan Bergerf53b93b2016-02-02 13:09:12 -050042/****************************************************************
43 * TPM 2 commands
44 ****************************************************************/
Kevin O'Connor27065322015-11-28 14:25:41 -050045
Stefan Bergerf53b93b2016-02-02 13:09:12 -050046static const u8 Startup_SU_CLEAR[] = { 0x00, TPM2_SU_CLEAR};
47static const u8 Startup_SU_STATE[] = { 0x00, TPM2_SU_STATE};
48
49static const u8 TPM2_SelfTest_YES[] = { TPM2_YES }; /* full test */
50
51
52typedef u8 tpm_ppi_code;
Stefan Bergerb310dfa2015-03-23 14:22:16 -040053
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050054/****************************************************************
Kevin O'Connor27065322015-11-28 14:25:41 -050055 * ACPI TCPA table interface
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050056 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040057
Kevin O'Connor27065322015-11-28 14:25:41 -050058struct {
Stefan Berger60bb9e92015-11-21 14:54:42 -050059 /* length of the TCPA log buffer */
60 u32 log_area_minimum_length;
61
62 /* start address of TCPA log buffer */
63 u8 * log_area_start_address;
64
65 /* number of log entries written */
66 u32 entry_count;
67
68 /* address to write next log entry to */
69 u8 * log_area_next_entry;
70
71 /* address of last entry written (need for TCG_StatusCheck) */
72 u8 * log_area_last_entry;
Kevin O'Connor27065322015-11-28 14:25:41 -050073} tpm_state VARLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050074
Stefan Berger115d0082016-01-07 12:02:49 -050075static int TPM_has_physical_presence;
76
Stefan Bergerefc49cf2016-02-02 13:09:09 -050077static TPMVersion TPM_version;
78
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050079static struct tcpa_descriptor_rev2 *
80find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
81{
Kevin O'Connor27065322015-11-28 14:25:41 -050082 if (!rsdp) {
83 dprintf(DEBUG_tcg,
84 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
85 return NULL;
86 }
87 struct rsdt_descriptor *rsdt = (void*)rsdp->rsdt_physical_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050088 if (!rsdt)
89 return NULL;
90
Kevin O'Connor27065322015-11-28 14:25:41 -050091 u32 length = rsdt->length;
92 u16 off = offsetof(struct rsdt_descriptor, entry);
93 u32 ctr = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050094 while ((off + sizeof(rsdt->entry[0])) <= length) {
95 /* try all pointers to structures */
Kevin O'Connor27065322015-11-28 14:25:41 -050096 struct tcpa_descriptor_rev2 *tcpa = (void*)rsdt->entry[ctr];
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050097
98 /* valid TCPA ACPI table ? */
Kevin O'Connor27065322015-11-28 14:25:41 -050099 if (tcpa->signature == TCPA_SIGNATURE
100 && checksum(tcpa, tcpa->length) == 0)
101 return tcpa;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500102
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500103 off += sizeof(rsdt->entry[0]);
104 ctr++;
105 }
106
Kevin O'Connor27065322015-11-28 14:25:41 -0500107 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
108 return NULL;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500109}
110
Kevin O'Connor27065322015-11-28 14:25:41 -0500111static int
112tpm_tcpa_probe(void)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500113{
Kevin O'Connor27065322015-11-28 14:25:41 -0500114 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_by_rsdp(RsdpAddr);
115 if (!tcpa)
116 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500117
Kevin O'Connor27065322015-11-28 14:25:41 -0500118 u8 *log_area_start_address = (u8*)(long)tcpa->log_area_start_address;
119 u32 log_area_minimum_length = tcpa->log_area_minimum_length;
120 if (!log_area_start_address || !log_area_minimum_length)
121 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500122
Kevin O'Connor27065322015-11-28 14:25:41 -0500123 memset(log_area_start_address, 0, log_area_minimum_length);
124 tpm_state.log_area_start_address = log_area_start_address;
125 tpm_state.log_area_minimum_length = log_area_minimum_length;
126 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500127 tpm_state.log_area_last_entry = NULL;
128 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -0500129 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500130}
131
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500132/*
133 * Extend the ACPI log with the given entry by copying the
134 * entry data into the log.
135 * Input
136 * pcpes : Pointer to the event 'header' to be copied into the log
137 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500138 *
139 * Output:
140 * Returns an error code in case of faiure, 0 in case of success
141 */
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500142static int
Kevin O'Connor93784032016-02-05 22:28:17 -0500143tpm_log_event(struct tcg_pcr_event2_sha1 *entry, const void *event
144 , TPMVersion tpm_version)
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'Connor93784032016-02-05 22:28:17 -0500152 u32 size = sizeof(*entry) + entry->eventdatasize;
153 u32 logsize = (tpm_state.log_area_next_entry + size
154 - tpm_state.log_area_start_address);
155 if (logsize > tpm_state.log_area_minimum_length) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500156 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'Connor93784032016-02-05 22:28:17 -0500160 switch (tpm_version) {
161 case TPM_VERSION_1_2: ;
162 struct pcpes *pcpes = (void*)tpm_state.log_area_next_entry;
163 pcpes->pcrindex = entry->pcrindex;
164 pcpes->eventtype = entry->eventtype;
165 memcpy(pcpes->digest, entry->digests[0].sha1, sizeof(pcpes->digest));
166 pcpes->eventdatasize = entry->eventdatasize;
167 memcpy(pcpes->event, event, entry->eventdatasize);
168 size = sizeof(*pcpes) + entry->eventdatasize;
169 break;
170 case TPM_VERSION_2: ;
171 struct tcg_pcr_event2_sha1 *e = (void*)tpm_state.log_area_next_entry;
172 memcpy(e, entry, sizeof(*e));
173 memcpy(e->event, event, entry->eventdatasize);
174 break;
175 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500176
177 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
178 tpm_state.log_area_next_entry += size;
179 tpm_state.entry_count++;
180
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500181 return 0;
182}
183
Kevin O'Connor93784032016-02-05 22:28:17 -0500184/*
185 * Initialize the log; a TPM2 log needs a special TPM 1.2 log entry
186 * as the first entry serving identification purposes
187 */
188static void
189tpm_log_init(void)
190{
191 struct TCG_EfiSpecIdEventStruct event = {
192 .signature = "Spec ID Event03",
193 .platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
194 .specVersionMinor = 0,
195 .specVersionMajor = 2,
196 .specErrata = 0,
197 .uintnSize = 2,
198 .numberOfAlgorithms = 1,
199 .digestSizes[0] = {
200 .algorithmId = TPM2_ALG_SHA1,
201 .digestSize = SHA1_BUFSIZE,
202 },
203 .vendorInfoSize = 0,
204 };
205 struct tcg_pcr_event2_sha1 entry = {
206 .eventtype = EV_NO_ACTION,
207 .eventdatasize = sizeof(event),
208 };
209
210 switch (TPM_version) {
211 case TPM_VERSION_1_2:
212 break;
213 case TPM_VERSION_2:
214 /* write a 1.2 type of entry */
215 tpm_log_event(&entry, &event, TPM_VERSION_1_2);
216 }
217}
218
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500219
220/****************************************************************
221 * Helper functions
222 ****************************************************************/
223
Kevin O'Connord559a232015-11-28 08:35:26 -0500224u8 TPM_working VARLOW;
225
Stefan Berger115d0082016-01-07 12:02:49 -0500226static int
Kevin O'Connord559a232015-11-28 08:35:26 -0500227tpm_is_working(void)
228{
229 return CONFIG_TCGBIOS && TPM_working;
230}
231
Stefan Berger115d0082016-01-07 12:02:49 -0500232int
233tpm_can_show_menu(void)
234{
Stefan Berger1d37d522016-02-02 13:09:11 -0500235 switch (TPM_version) {
236 case TPM_VERSION_1_2:
237 return tpm_is_working() && TPM_has_physical_presence;
238 case TPM_VERSION_2:
239 return tpm_is_working();
240 }
241 return 0;
Stefan Berger115d0082016-01-07 12:02:49 -0500242}
243
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400244/*
245 * Send a TPM command with the given ordinal. Append the given buffer
246 * containing all data in network byte order to the command (this is
247 * the custom part per command) and expect a response of the given size.
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400248 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500249static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500250tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append,
251 u32 append_size, enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400252{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500253 struct {
254 struct tpm_req_header trqh;
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500255 u8 cmd[10];
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500256 } PACKED req = {
257 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500258 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500259 .trqh.ordinal = cpu_to_be32(ordinal),
260 };
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500261
262 switch (TPM_version) {
263 case TPM_VERSION_1_2:
264 req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
265 break;
266 case TPM_VERSION_2:
267 req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
268 break;
269 }
270
Stefan Bergerece25612015-11-12 10:14:46 -0500271 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400272 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400273 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400274 memset(obuffer, 0x0, sizeof(obuffer));
275
Kevin O'Connor71479612015-12-29 14:32:19 -0500276 if (append_size > sizeof(req.cmd)) {
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500277 warn_internalerror();
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500278 return -1;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500279 }
280 if (append_size)
281 memcpy(req.cmd, append, append_size);
282
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500283 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
284 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500285 dprintf(DEBUG_tcg, "Return from build_and_send_cmd(%x, %x %x) = %x\n",
286 ordinal, req.cmd[0], req.cmd[1], ret);
287 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400288}
289
Stefan Bergere444dce2016-02-02 13:09:17 -0500290static int
291tpm20_hierarchycontrol(u32 hierarchy, u8 state)
292{
293 /* we will try to deactivate the TPM now - ignoring all errors */
294 struct tpm2_req_hierarchycontrol trh = {
295 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
296 .hdr.totlen = cpu_to_be32(sizeof(trh)),
297 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
298 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
299 .authblocksize = cpu_to_be32(sizeof(trh.authblock)),
300 .authblock = {
301 .handle = cpu_to_be32(TPM2_RS_PW),
302 .noncesize = cpu_to_be16(0),
303 .contsession = TPM2_YES,
304 .pwdsize = cpu_to_be16(0),
305 },
306 .enable = cpu_to_be32(hierarchy),
307 .state = state,
308 };
309 struct tpm_rsp_header rsp;
310 u32 resp_length = sizeof(rsp);
311 int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,
312 TPM_DURATION_TYPE_MEDIUM);
313 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
314 ret = -1;
315
316 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",
317 ret);
318
319 return ret;
320}
321
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500322static void
323tpm_set_failure(void)
324{
Stefan Berger1d37d522016-02-02 13:09:11 -0500325 switch (TPM_version) {
326 case TPM_VERSION_1_2:
327 /*
328 * We will try to deactivate the TPM now - ignoring all errors
329 * Physical presence is asserted.
330 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500331
Stefan Berger1d37d522016-02-02 13:09:11 -0500332 tpm_build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
333 NULL, 0, TPM_DURATION_TYPE_SHORT);
334 break;
335 case TPM_VERSION_2:
Stefan Bergere444dce2016-02-02 13:09:17 -0500336 tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
337 tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
Stefan Berger1d37d522016-02-02 13:09:11 -0500338 break;
339 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500340
Kevin O'Connord559a232015-11-28 08:35:26 -0500341 TPM_working = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500342}
343
Kevin O'Connorca606362015-12-29 14:21:29 -0500344static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500345tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
Kevin O'Connorca606362015-12-29 14:21:29 -0500346{
347 struct tpm_req_getcap trgc = {
348 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
349 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
350 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
351 .capArea = cpu_to_be32(cap),
352 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
353 .subCap = cpu_to_be32(subcap)
354 };
355 u32 resp_size = rsize;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500356 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
357 TPM_DURATION_TYPE_SHORT);
358 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
Kevin O'Connorca606362015-12-29 14:21:29 -0500359 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
360 " = %x\n", cap, subcap, ret);
361 if (ret) {
362 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
363 tpm_set_failure();
364 }
365 return ret;
366}
367
368static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500369tpm12_determine_timeouts(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400370{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400371 struct tpm_res_getcap_timeouts timeouts;
Stefan Berger1d37d522016-02-02 13:09:11 -0500372 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
373 , &timeouts.hdr, sizeof(timeouts));
Kevin O'Connorca606362015-12-29 14:21:29 -0500374 if (ret)
375 return ret;
376
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400377 struct tpm_res_getcap_durations durations;
Stefan Berger1d37d522016-02-02 13:09:11 -0500378 ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
379 , &durations.hdr, sizeof(durations));
Kevin O'Connorca606362015-12-29 14:21:29 -0500380 if (ret)
381 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400382
Kevin O'Connorca606362015-12-29 14:21:29 -0500383 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400384 for (i = 0; i < 3; i++)
385 durations.durations[i] = be32_to_cpu(durations.durations[i]);
386
387 for (i = 0; i < 4; i++)
388 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
389
390 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
391 timeouts.timeouts[0],
392 timeouts.timeouts[1],
393 timeouts.timeouts[2],
394 timeouts.timeouts[3]);
395
396 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
397 durations.durations[0],
398 durations.durations[1],
399 durations.durations[2]);
400
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500401 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400402
403 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400404}
405
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500406static void
407tpm20_set_timeouts(void)
408{
409 u32 durations[3] = {
410 TPM2_DEFAULT_DURATION_SHORT,
411 TPM2_DEFAULT_DURATION_MEDIUM,
412 TPM2_DEFAULT_DURATION_LONG,
413 };
414 u32 timeouts[4] = {
415 TIS2_DEFAULT_TIMEOUT_A,
416 TIS2_DEFAULT_TIMEOUT_B,
417 TIS2_DEFAULT_TIMEOUT_C,
418 TIS2_DEFAULT_TIMEOUT_D,
419 };
420
421 tpmhw_set_timeouts(timeouts, durations);
422}
423
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500424static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500425tpm12_extend(u32 pcrindex, const u8 *digest)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500426{
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500427 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500428 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
429 .hdr.totlen = cpu_to_be32(sizeof(tre)),
430 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500431 .pcrindex = cpu_to_be32(pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500432 };
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500433 memcpy(tre.digest, digest, sizeof(tre.digest));
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500434
435 struct tpm_rsp_extend rsp;
436 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500437 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
438 TPM_DURATION_TYPE_SHORT);
439 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500440 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500441
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500442 return 0;
443}
444
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500445static int tpm20_extend(u32 pcrindex, const u8 *digest)
446{
447 struct tpm2_req_extend tre = {
448 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
449 .hdr.totlen = cpu_to_be32(sizeof(tre)),
450 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
451 .pcrindex = cpu_to_be32(pcrindex),
452 .authblocksize = cpu_to_be32(sizeof(tre.authblock)),
453 .authblock = {
454 .handle = cpu_to_be32(TPM2_RS_PW),
455 .noncesize = cpu_to_be16(0),
456 .contsession = TPM2_YES,
457 .pwdsize = cpu_to_be16(0),
458 },
459 .digest = {
460 .count = cpu_to_be32(1),
461 .hashalg = cpu_to_be16(TPM2_ALG_SHA1),
462 },
463 };
464 memcpy(tre.digest.sha1, digest, sizeof(tre.digest.sha1));
465
466 struct tpm_rsp_header rsp;
467 u32 resp_length = sizeof(rsp);
468 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
469 TPM_DURATION_TYPE_SHORT);
470 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
471 return -1;
472
473 return 0;
474}
475
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500476static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500477tpm_extend(u32 pcrindex, const u8 *digest)
478{
Stefan Berger1d37d522016-02-02 13:09:11 -0500479 switch (TPM_version) {
480 case TPM_VERSION_1_2:
481 return tpm12_extend(pcrindex, digest);
482 case TPM_VERSION_2:
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500483 return tpm20_extend(pcrindex, digest);
Stefan Berger1d37d522016-02-02 13:09:11 -0500484 }
485 return -1;
486}
487
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500488/*
489 * Add a measurement to the log; the data at data_seg:data/length are
490 * appended to the TCG_PCClientPCREventStruct
491 *
492 * Input parameters:
493 * pcrindex : which PCR to extend
494 * event_type : type of event; specs section on 'Event Types'
495 * event : pointer to info (e.g., string) to be added to log as-is
496 * event_length: length of the event
497 * hashdata : pointer to the data to be hashed
498 * hashdata_length: length of the data to be hashed
499 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500500static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500501tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
502 const char *event, u32 event_length,
503 const u8 *hashdata, u32 hashdata_length)
504{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500505 if (!tpm_is_working())
506 return;
507
Kevin O'Connor93784032016-02-05 22:28:17 -0500508 struct tcg_pcr_event2_sha1 entry = {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500509 .pcrindex = pcrindex,
510 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500511 .eventdatasize = event_length,
Kevin O'Connor93784032016-02-05 22:28:17 -0500512 .count = 1,
513 .digests[0].hashtype = TPM2_ALG_SHA1,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500514 };
Kevin O'Connor93784032016-02-05 22:28:17 -0500515 sha1(hashdata, hashdata_length, entry.digests[0].sha1);
516 int ret = tpm_extend(entry.pcrindex, entry.digests[0].sha1);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500517 if (ret) {
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500518 tpm_set_failure();
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500519 return;
520 }
Kevin O'Connor93784032016-02-05 22:28:17 -0500521 tpm_log_event(&entry, event, TPM_version);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500522}
523
524
525/****************************************************************
526 * Setup and Measurements
527 ****************************************************************/
528
Kevin O'Connora6175422015-11-22 11:28:14 -0500529// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500530static void
Kevin O'Connora6175422015-11-22 11:28:14 -0500531tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500532{
Kevin O'Connora6175422015-11-22 11:28:14 -0500533 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500534 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
535 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500536}
537
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500538/*
539 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
540 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500541static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500542tpm_add_event_separators(void)
543{
Kevin O'Connora6175422015-11-22 11:28:14 -0500544 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500545 u32 pcrIndex;
546 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
547 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
548 NULL, 0,
549 evt_separator,
550 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500551}
552
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500553static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500554tpm_smbios_measure(void)
555{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500556 struct pcctes pcctes = {
557 .eventid = 1,
558 .eventdatasize = SHA1_BUFSIZE,
559 };
560 struct smbios_entry_point *sep = SMBiosAddr;
561
562 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
563
564 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500565 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500566
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500567 sha1((const u8 *)sep->structure_table_address,
568 sep->structure_table_length, pcctes.digest);
569 tpm_add_measurement_to_log(1,
570 EV_EVENT_TAG,
571 (const char *)&pcctes, sizeof(pcctes),
572 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500573}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400574
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500575static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500576tpm12_read_permanent_flags(char *buf, int buf_len)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500577{
578 memset(buf, 0, buf_len);
579
580 struct tpm_res_getcap_perm_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -0500581 int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
582 , &pf.hdr, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500583 if (ret)
584 return -1;
585
586 memcpy(buf, &pf.perm_flags, buf_len);
587
588 return 0;
589}
590
591static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500592tpm12_assert_physical_presence(void)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500593{
Stefan Berger1d37d522016-02-02 13:09:11 -0500594 int ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
595 PhysicalPresence_PRESENT,
596 sizeof(PhysicalPresence_PRESENT),
597 TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500598 if (!ret)
599 return 0;
600
601 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -0500602 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500603 if (ret)
604 return -1;
605
Stefan Bergera2206d32016-01-07 12:02:48 -0500606 /* check if hardware physical presence is supported */
607 if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
608 /* HW phys. presence may not be asserted... */
Stefan Bergere55e37f2016-01-07 12:02:47 -0500609 return 0;
Stefan Bergere55e37f2016-01-07 12:02:47 -0500610 }
611
Stefan Bergera2206d32016-01-07 12:02:48 -0500612 if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
613 && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
Stefan Berger1d37d522016-02-02 13:09:11 -0500614 tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
615 PhysicalPresence_CMD_ENABLE,
616 sizeof(PhysicalPresence_CMD_ENABLE),
617 TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500618
Stefan Berger1d37d522016-02-02 13:09:11 -0500619 return tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
620 PhysicalPresence_PRESENT,
621 sizeof(PhysicalPresence_PRESENT),
622 TPM_DURATION_TYPE_SHORT);
Stefan Bergere55e37f2016-01-07 12:02:47 -0500623 }
Stefan Bergere55e37f2016-01-07 12:02:47 -0500624 return -1;
625}
626
627static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500628tpm12_startup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400629{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400630 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger1d37d522016-02-02 13:09:11 -0500631 int ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup,
632 Startup_ST_CLEAR,
633 sizeof(Startup_ST_CLEAR),
634 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500635 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400636 /* with other firmware on the system the TPM may already have been
637 * initialized
638 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500639 ret = 0;
640 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400641 goto err_exit;
642
Stefan Berger115d0082016-01-07 12:02:49 -0500643 /* assertion of physical presence is only possible after startup */
Stefan Berger1d37d522016-02-02 13:09:11 -0500644 ret = tpm12_assert_physical_presence();
Stefan Berger115d0082016-01-07 12:02:49 -0500645 if (!ret)
646 TPM_has_physical_presence = 1;
647
Stefan Berger1d37d522016-02-02 13:09:11 -0500648 ret = tpm12_determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -0500649 if (ret)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500650 return -1;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500651
Stefan Berger1d37d522016-02-02 13:09:11 -0500652 ret = tpm_build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
653 TPM_DURATION_TYPE_LONG);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500654 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400655 goto err_exit;
656
Stefan Berger1d37d522016-02-02 13:09:11 -0500657 ret = tpm_build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
658 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500659 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400660 goto err_exit;
661
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400662 return 0;
663
664err_exit:
665 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
666
Stefan Berger7fce1d92015-11-12 10:14:45 -0500667 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500668 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400669}
670
Stefan Berger1d37d522016-02-02 13:09:11 -0500671static int
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500672tpm20_startup(void)
673{
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500674 tpm20_set_timeouts();
675
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500676 int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
677 Startup_SU_CLEAR,
678 sizeof(Startup_SU_CLEAR),
679 TPM_DURATION_TYPE_SHORT);
680
681 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
682 ret);
683
684 if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
685 /* with other firmware on the system the TPM may already have been
686 * initialized
687 */
688 ret = 0;
689
690 if (ret)
691 goto err_exit;
692
693 ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest,
694 TPM2_SelfTest_YES,
695 sizeof(TPM2_SelfTest_YES),
696 TPM_DURATION_TYPE_LONG);
697
698 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n",
699 ret);
700
701 if (ret)
702 goto err_exit;
703
704 return 0;
705
706err_exit:
707 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
708
709 tpm_set_failure();
710 return -1;
711}
712
713static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500714tpm_startup(void)
715{
716 switch (TPM_version) {
717 case TPM_VERSION_1_2:
718 return tpm12_startup();
719 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500720 return tpm20_startup();
Stefan Berger1d37d522016-02-02 13:09:11 -0500721 }
722 return -1;
723}
724
Kevin O'Connord6aca442015-06-10 11:00:17 -0400725void
726tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400727{
728 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400729 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400730
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500731 TPM_version = tpmhw_probe();
732 if (TPM_version == TPM_VERSION_NONE)
Kevin O'Connor27065322015-11-28 14:25:41 -0500733 return;
734
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500735 dprintf(DEBUG_tcg,
736 "TCGBIOS: Detected a TPM %s.\n",
737 (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
738
739 int ret = tpm_tcpa_probe();
Kevin O'Connor27065322015-11-28 14:25:41 -0500740 if (ret)
741 return;
742
Kevin O'Connor93784032016-02-05 22:28:17 -0500743 tpm_log_init();
744
Kevin O'Connor27065322015-11-28 14:25:41 -0500745 TPM_working = 1;
746
Quan Xu67643952015-04-30 19:43:04 -0400747 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400748 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400749
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500750 ret = tpm_startup();
751 if (ret)
752 return;
753
754 tpm_smbios_measure();
755 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400756}
757
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500758static int
759tpm20_stirrandom(void)
760{
761 struct tpm2b_stir stir = {
762 .size = cpu_to_be16(sizeof(stir.stir)),
763 .stir = rdtscll(),
764 };
765 /* set more bits to stir with */
766 stir.stir += swab64(rdtscll());
767
768 int ret = tpm_build_and_send_cmd(0, TPM2_CC_StirRandom,
769 (u8 *)&stir, sizeof(stir),
770 TPM_DURATION_TYPE_SHORT);
771
772 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
773 ret);
774
775 return ret;
776}
777
778static int
779tpm20_getrandom(u8 *buf, u16 buf_len)
780{
781 struct tpm2_res_getrandom rsp;
782
783 if (buf_len > sizeof(rsp.rnd.buffer))
784 return -1;
785
786 struct tpm2_req_getrandom trgr = {
787 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
788 .hdr.totlen = cpu_to_be32(sizeof(trgr)),
789 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
790 .bytesRequested = cpu_to_be16(buf_len),
791 };
792 u32 resp_length = sizeof(rsp);
793
794 int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
795 TPM_DURATION_TYPE_MEDIUM);
796 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
797 ret = -1;
798 else
799 memcpy(buf, rsp.rnd.buffer, buf_len);
800
801 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
802 ret);
803
804 return ret;
805}
806
807static int
808tpm20_hierarchychangeauth(u8 auth[20])
809{
810 struct tpm2_req_hierarchychangeauth trhca = {
811 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
812 .hdr.totlen = cpu_to_be32(sizeof(trhca)),
813 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
814 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
815 .authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
816 .authblock = {
817 .handle = cpu_to_be32(TPM2_RS_PW),
818 .noncesize = cpu_to_be16(0),
819 .contsession = TPM2_YES,
820 .pwdsize = cpu_to_be16(0),
821 },
822 .newAuth = {
823 .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
824 },
825 };
826 memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
827
828 struct tpm_rsp_header rsp;
829 u32 resp_length = sizeof(rsp);
830 int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
831 TPM_DURATION_TYPE_MEDIUM);
832 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
833 ret = -1;
834
835 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
836 ret);
837
838 return ret;
839}
840
841static void
842tpm20_prepboot(void)
843{
844 int ret = tpm20_stirrandom();
845 if (ret)
846 goto err_exit;
847
848 u8 auth[20];
849 ret = tpm20_getrandom(&auth[0], sizeof(auth));
850 if (ret)
851 goto err_exit;
852
853 ret = tpm20_hierarchychangeauth(auth);
854 if (ret)
855 goto err_exit;
856
857 return;
858
859err_exit:
860 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
861
862 tpm_set_failure();
863}
864
Kevin O'Connord6aca442015-06-10 11:00:17 -0400865void
866tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400867{
Stefan Berger8b902b82016-01-07 12:02:50 -0500868 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400869 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400870
Stefan Berger1d37d522016-02-02 13:09:11 -0500871 switch (TPM_version) {
872 case TPM_VERSION_1_2:
873 if (TPM_has_physical_presence)
874 tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
875 PhysicalPresence_NOT_PRESENT_LOCK,
876 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
877 TPM_DURATION_TYPE_SHORT);
878 break;
879 case TPM_VERSION_2:
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500880 tpm20_prepboot();
Stefan Berger1d37d522016-02-02 13:09:11 -0500881 break;
882 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400883
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500884 tpm_add_action(4, "Calling INT 19h");
885 tpm_add_event_separators();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400886}
887
Stefan Berger5aa2a752015-03-23 14:22:17 -0400888/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500889 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400890 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500891void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500892tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400893{
Kevin O'Connord559a232015-11-28 08:35:26 -0500894 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500895 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500896
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500897 struct pcctes_romex pcctes = {
898 .eventid = 7,
899 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400900 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500901 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500902 tpm_add_measurement_to_log(2,
903 EV_EVENT_TAG,
904 (const char *)&pcctes, sizeof(pcctes),
905 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500906}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400907
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500908void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400909tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
910{
Kevin O'Connord559a232015-11-28 08:35:26 -0500911 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500912 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400913
Stefan Berger4cdbc412015-11-30 11:14:18 -0500914 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500915 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -0500916
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500917 const char *string = "Booting BCV device 00h (Floppy)";
918 if (bootdrv == 0x80)
919 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500920 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400921
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500922 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
923 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500924 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500925 tpm_add_measurement_to_log(4, EV_IPL,
926 string, strlen(string),
927 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500928
929 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
930 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500931 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
932 string, strlen(string),
933 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400934}
935
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500936void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400937tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
938{
Kevin O'Connord559a232015-11-28 08:35:26 -0500939 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500940 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400941
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500942 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400943
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500944 /* specs: see section 'El Torito' */
945 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500946 tpm_add_measurement_to_log(4, EV_IPL,
947 string, strlen(string),
948 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400949}
950
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500951void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400952tpm_add_cdrom_catalog(const u8 *addr, u32 length)
953{
Kevin O'Connord559a232015-11-28 08:35:26 -0500954 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500955 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400956
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500957 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400958
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500959 /* specs: see section 'El Torito' */
960 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500961 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
962 string, strlen(string),
963 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400964}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400965
Kevin O'Connord6aca442015-06-10 11:00:17 -0400966void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400967tpm_s3_resume(void)
968{
Kevin O'Connord559a232015-11-28 08:35:26 -0500969 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400970 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400971
972 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
973
Stefan Berger1d37d522016-02-02 13:09:11 -0500974 int ret = -1;
975
976 switch (TPM_version) {
977 case TPM_VERSION_1_2:
978 ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup,
979 Startup_ST_STATE,
980 sizeof(Startup_ST_STATE),
981 TPM_DURATION_TYPE_SHORT);
982 break;
983 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500984 ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
985 Startup_SU_STATE,
986 sizeof(Startup_SU_STATE),
987 TPM_DURATION_TYPE_SHORT);
988
989 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n",
990 ret);
991
992 if (ret)
993 goto err_exit;
994
995
996 ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest,
997 TPM2_SelfTest_YES, sizeof(TPM2_SelfTest_YES),
998 TPM_DURATION_TYPE_LONG);
999
1000 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n",
1001 ret);
1002
Stefan Berger1d37d522016-02-02 13:09:11 -05001003 break;
1004 }
1005
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001006 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001007 goto err_exit;
1008
Kevin O'Connord6aca442015-06-10 11:00:17 -04001009 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001010
1011err_exit:
1012 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1013
Stefan Berger7fce1d92015-11-12 10:14:45 -05001014 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001015}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001016
1017
1018/****************************************************************
1019 * BIOS interface
1020 ****************************************************************/
1021
Kevin O'Connor59076132015-11-28 13:55:09 -05001022u8 TPM_interface_shutdown VARLOW;
1023
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001024static inline void *input_buf32(struct bregs *regs)
1025{
1026 return MAKE_FLATPTR(regs->es, regs->di);
1027}
1028
1029static inline void *output_buf32(struct bregs *regs)
1030{
1031 return MAKE_FLATPTR(regs->ds, regs->si);
1032}
1033
1034static u32
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001035hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
1036 , void *event, int extend)
1037{
1038 if (pcpes->pcrindex >= 24)
1039 return TCG_INVALID_INPUT_PARA;
1040 if (hashdata)
1041 sha1(hashdata, hashdata_length, pcpes->digest);
1042 if (extend) {
1043 int ret = tpm_extend(pcpes->pcrindex, pcpes->digest);
1044 if (ret)
1045 return TCG_TCG_COMMAND_ERROR;
1046 }
Kevin O'Connor93784032016-02-05 22:28:17 -05001047 struct tcg_pcr_event2_sha1 entry = {
1048 .pcrindex = pcpes->pcrindex,
1049 .eventtype = pcpes->eventtype,
1050 .eventdatasize = pcpes->eventdatasize,
1051 .count = 1,
1052 .digests[0].hashtype = TPM2_ALG_SHA1,
1053 };
1054 memcpy(entry.digests[0].sha1, pcpes->digest, sizeof(entry.digests[0].sha1));
1055 int ret = tpm_log_event(&entry, pcpes->event, TPM_version);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001056 if (ret)
1057 return TCG_PC_LOGOVERFLOW;
1058 return 0;
1059}
1060
1061static u32
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001062hash_log_extend_event_int(const struct hleei_short *hleei_s,
1063 struct hleeo *hleeo)
1064{
1065 u32 rc = 0;
1066 struct hleo hleo;
1067 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
1068 const void *logdataptr;
1069 u32 logdatalen;
1070 struct pcpes *pcpes;
1071 u32 pcrindex;
1072
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001073 /* short or long version? */
1074 switch (hleei_s->ipblength) {
1075 case sizeof(struct hleei_short):
1076 /* short */
1077 logdataptr = hleei_s->logdataptr;
1078 logdatalen = hleei_s->logdatalen;
1079 pcrindex = hleei_s->pcrindex;
1080 break;
1081
1082 case sizeof(struct hleei_long):
1083 /* long */
1084 logdataptr = hleei_l->logdataptr;
1085 logdatalen = hleei_l->logdatalen;
1086 pcrindex = hleei_l->pcrindex;
1087 break;
1088
1089 default:
1090 /* bad input block */
1091 rc = TCG_INVALID_INPUT_PARA;
1092 goto err_exit;
1093 }
1094
1095 pcpes = (struct pcpes *)logdataptr;
1096
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001097 if (pcpes->pcrindex != pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001098 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001099 rc = TCG_INVALID_INPUT_PARA;
1100 goto err_exit;
1101 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001102 rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen
1103 , pcpes->event, 1);
1104 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001105 goto err_exit;
1106
1107 hleeo->opblength = sizeof(struct hleeo);
1108 hleeo->reserved = 0;
1109 hleeo->eventnumber = hleo.eventnumber;
Stefan Berger2b237502016-01-07 12:02:46 -05001110 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001111
1112err_exit:
1113 if (rc != 0) {
1114 hleeo->opblength = 4;
1115 hleeo->reserved = 0;
1116 }
1117
1118 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001119}
1120
1121static u32
1122pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
1123{
1124 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001125 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001126
Stefan Berger7092de32016-02-02 13:09:19 -05001127 if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh)
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001128 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
1129 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001130 rc = TCG_INVALID_INPUT_PARA;
1131 goto err_exit;
1132 }
1133
Stefan Berger7092de32016-02-02 13:09:19 -05001134 u16 tag = be16_to_cpu(trh->tag);
1135
1136 switch (TPM_version) {
1137 case TPM_VERSION_1_2:
1138 if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD
1139 && tag != TPM_TAG_RQU_AUTH2_CMD) {
1140 rc = TCG_INVALID_INPUT_PARA;
1141 goto err_exit;
1142 }
1143 break;
1144 case TPM_VERSION_2:
1145 if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) {
1146 rc = TCG_INVALID_INPUT_PARA;
1147 goto err_exit;
1148 }
1149 }
1150
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001151 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001152 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
1153 TPM_DURATION_TYPE_LONG /* worst case */);
1154 if (ret) {
1155 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001156 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001157 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001158
1159 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
1160 pttto->reserved = 0;
1161
1162err_exit:
1163 if (rc != 0) {
1164 pttto->opblength = 4;
1165 pttto->reserved = 0;
1166 }
1167
1168 return rc;
1169}
1170
1171static u32
1172shutdown_preboot_interface(void)
1173{
Kevin O'Connor59076132015-11-28 13:55:09 -05001174 TPM_interface_shutdown = 1;
1175 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001176}
1177
1178static u32
1179hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1180{
1181 u32 rc = 0;
1182 u16 size;
1183 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001184
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001185 size = hlei->ipblength;
1186 if (size != sizeof(*hlei)) {
1187 rc = TCG_INVALID_INPUT_PARA;
1188 goto err_exit;
1189 }
1190
1191 pcpes = (struct pcpes *)hlei->logdataptr;
1192
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001193 if (pcpes->pcrindex != hlei->pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001194 || pcpes->eventtype != hlei->logeventtype
1195 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001196 rc = TCG_INVALID_INPUT_PARA;
1197 goto err_exit;
1198 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001199 rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen
1200 , pcpes->event, 0);
1201 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001202 goto err_exit;
1203
1204 /* updating the log was fine */
1205 hleo->opblength = sizeof(struct hleo);
1206 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001207 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001208
1209err_exit:
1210 if (rc != 0) {
1211 hleo->opblength = 2;
1212 hleo->reserved = 0;
1213 }
1214
1215 return rc;
1216}
1217
1218static u32
1219hash_all_int(const struct hai *hai, u8 *hash)
1220{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001221 if (hai->ipblength != sizeof(struct hai) ||
1222 hai->hashdataptr == 0 ||
1223 hai->hashdatalen == 0 ||
1224 hai->algorithmid != TPM_ALG_SHA)
1225 return TCG_INVALID_INPUT_PARA;
1226
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001227 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1228 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001229}
1230
1231static u32
1232tss_int(struct ti *ti, struct to *to)
1233{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001234 to->opblength = sizeof(struct to);
1235 to->reserved = 0;
1236
Kevin O'Connor59076132015-11-28 13:55:09 -05001237 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001238}
1239
1240static u32
1241compact_hash_log_extend_event_int(u8 *buffer,
1242 u32 info,
1243 u32 length,
1244 u32 pcrindex,
1245 u32 *edx_ptr)
1246{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001247 struct pcpes pcpes = {
1248 .pcrindex = pcrindex,
1249 .eventtype = EV_COMPACT_HASH,
1250 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001251 };
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001252 u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1);
1253 if (rc)
1254 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001255
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001256 *edx_ptr = tpm_state.entry_count;
1257 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001258}
1259
1260void VISIBLE32FLAT
1261tpm_interrupt_handler32(struct bregs *regs)
1262{
1263 if (!CONFIG_TCGBIOS)
1264 return;
1265
1266 set_cf(regs, 0);
1267
Kevin O'Connor59076132015-11-28 13:55:09 -05001268 if (TPM_interface_shutdown && regs->al) {
1269 regs->eax = TCG_INTERFACE_SHUTDOWN;
1270 return;
1271 }
1272
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001273 switch ((enum irq_ids)regs->al) {
1274 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -05001275 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001276 /* no TPM available */
1277 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1278 } else {
1279 regs->eax = 0;
1280 regs->ebx = TCG_MAGIC;
1281 regs->ch = TCG_VERSION_MAJOR;
1282 regs->cl = TCG_VERSION_MINOR;
1283 regs->edx = 0x0;
1284 regs->esi = (u32)tpm_state.log_area_start_address;
1285 regs->edi = (u32)tpm_state.log_area_last_entry;
1286 }
1287 break;
1288
1289 case TCG_HashLogExtendEvent:
1290 regs->eax =
1291 hash_log_extend_event_int(
1292 (struct hleei_short *)input_buf32(regs),
1293 (struct hleeo *)output_buf32(regs));
1294 break;
1295
1296 case TCG_PassThroughToTPM:
1297 regs->eax =
1298 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1299 (struct pttto *)output_buf32(regs));
1300 break;
1301
1302 case TCG_ShutdownPreBootInterface:
1303 regs->eax = shutdown_preboot_interface();
1304 break;
1305
1306 case TCG_HashLogEvent:
1307 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1308 (struct hleo*)output_buf32(regs));
1309 break;
1310
1311 case TCG_HashAll:
1312 regs->eax =
1313 hash_all_int((struct hai*)input_buf32(regs),
1314 (u8 *)output_buf32(regs));
1315 break;
1316
1317 case TCG_TSS:
1318 regs->eax = tss_int((struct ti*)input_buf32(regs),
1319 (struct to*)output_buf32(regs));
1320 break;
1321
1322 case TCG_CompactHashLogExtendEvent:
1323 regs->eax =
1324 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1325 regs->esi,
1326 regs->ecx,
1327 regs->edx,
1328 &regs->edx);
1329 break;
1330
1331 default:
1332 set_cf(regs, 1);
1333 }
1334
1335 return;
1336}
Stefan Berger320df852015-11-30 11:14:19 -05001337
Kevin O'Connor26e36172015-12-29 12:20:23 -05001338
1339/****************************************************************
1340 * TPM Configuration Menu
1341 ****************************************************************/
1342
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001343static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001344tpm12_read_has_owner(int *has_owner)
Stefan Berger320df852015-11-30 11:14:19 -05001345{
Stefan Berger320df852015-11-30 11:14:19 -05001346 struct tpm_res_getcap_ownerauth oauth;
Stefan Berger1d37d522016-02-02 13:09:11 -05001347 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
1348 , &oauth.hdr, sizeof(oauth));
Kevin O'Connorca606362015-12-29 14:21:29 -05001349 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001350 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001351
1352 *has_owner = oauth.flag;
1353
1354 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001355}
1356
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001357static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001358tpm12_enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001359{
Stefan Berger320df852015-11-30 11:14:19 -05001360 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001361 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001362 if (ret)
1363 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001364
1365 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1366 return 0;
1367
Stefan Berger1d37d522016-02-02 13:09:11 -05001368 ret = tpm_build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
1369 : TPM_ORD_PhysicalDisable,
1370 NULL, 0, TPM_DURATION_TYPE_SHORT);
Stefan Berger44250252016-01-07 12:02:51 -05001371 if (ret) {
1372 if (enable)
1373 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1374 else
1375 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1376 }
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001377 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001378}
1379
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001380static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001381tpm12_activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001382{
Stefan Berger320df852015-11-30 11:14:19 -05001383 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001384 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001385 if (ret)
1386 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001387
1388 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1389 return 0;
1390
1391 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1392 return 0;
1393
Stefan Berger1d37d522016-02-02 13:09:11 -05001394 ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1395 activate ? CommandFlag_FALSE
1396 : CommandFlag_TRUE,
1397 activate ? sizeof(CommandFlag_FALSE)
1398 : sizeof(CommandFlag_TRUE),
1399 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001400 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001401 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001402
1403 if (activate && allow_reset) {
1404 if (verbose) {
1405 printf("Requiring a reboot to activate the TPM.\n");
1406
1407 msleep(2000);
1408 }
1409 reset();
1410 }
1411
1412 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001413}
1414
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001415static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001416tpm12_enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001417{
Stefan Berger1d37d522016-02-02 13:09:11 -05001418 int ret = tpm12_enable_tpm(1, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001419 if (ret)
1420 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001421
Stefan Berger1d37d522016-02-02 13:09:11 -05001422 return tpm12_activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001423}
1424
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001425static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001426tpm12_force_clear(int enable_activate_before, int enable_activate_after,
1427 int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001428{
Stefan Berger320df852015-11-30 11:14:19 -05001429 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001430 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001431 if (ret)
1432 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001433 if (!has_owner) {
1434 if (verbose)
1435 printf("TPM does not have an owner.\n");
1436 return 0;
1437 }
1438
1439 if (enable_activate_before) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001440 ret = tpm12_enable_activate(0, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001441 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001442 dprintf(DEBUG_tcg,
1443 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001444 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001445 }
1446 }
1447
Stefan Berger1d37d522016-02-02 13:09:11 -05001448 ret = tpm_build_and_send_cmd(0, TPM_ORD_ForceClear,
1449 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001450 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001451 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001452
1453 if (!enable_activate_after) {
1454 if (verbose)
1455 printf("Owner successfully cleared.\n"
1456 "You will need to enable/activate the TPM again.\n\n");
1457 return 0;
1458 }
1459
Stefan Berger1d37d522016-02-02 13:09:11 -05001460 return tpm12_enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001461}
1462
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001463static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001464tpm12_set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001465{
Stefan Berger320df852015-11-30 11:14:19 -05001466 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001467 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001468 if (ret)
1469 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001470 if (has_owner) {
1471 if (verbose)
1472 printf("Must first remove owner.\n");
1473 return 0;
1474 }
1475
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001476 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001477 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001478 if (ret)
1479 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001480
1481 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1482 if (verbose)
1483 printf("TPM must first be enable.\n");
1484 return 0;
1485 }
1486
Stefan Berger1d37d522016-02-02 13:09:11 -05001487 ret = tpm_build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1488 (allow) ? CommandFlag_TRUE
1489 : CommandFlag_FALSE,
1490 sizeof(CommandFlag_TRUE),
1491 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001492 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001493 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001494
1495 if (verbose)
1496 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1497
1498 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001499}
1500
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001501static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001502tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001503{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001504 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001505
1506 switch (msgCode) {
1507 case TPM_PPI_OP_NOOP: /* no-op */
1508 break;
1509
1510 case TPM_PPI_OP_ENABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001511 ret = tpm12_enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001512 break;
1513
1514 case TPM_PPI_OP_DISABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001515 ret = tpm12_enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001516 break;
1517
1518 case TPM_PPI_OP_ACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001519 ret = tpm12_activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001520 break;
1521
1522 case TPM_PPI_OP_DEACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001523 ret = tpm12_activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001524 break;
1525
1526 case TPM_PPI_OP_CLEAR:
Stefan Berger1d37d522016-02-02 13:09:11 -05001527 ret = tpm12_force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001528 break;
1529
1530 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001531 ret = tpm12_set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001532 break;
1533
1534 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001535 ret = tpm12_set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001536 break;
1537
1538 default:
1539 break;
1540 }
1541
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001542 if (ret)
1543 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001544
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001545 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001546}
1547
1548static int
Stefan Berger7d596dc2016-02-02 13:09:16 -05001549tpm20_clearcontrol(u8 disable, int verbose)
1550{
1551 struct tpm2_req_clearcontrol trc = {
1552 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1553 .hdr.totlen = cpu_to_be32(sizeof(trc)),
1554 .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
1555 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1556 .authblocksize = cpu_to_be32(sizeof(trc.authblock)),
1557 .authblock = {
1558 .handle = cpu_to_be32(TPM2_RS_PW),
1559 .noncesize = cpu_to_be16(0),
1560 .contsession = TPM2_YES,
1561 .pwdsize = cpu_to_be16(0),
1562 },
1563 .disable = disable,
1564 };
1565 struct tpm_rsp_header rsp;
1566 u32 resp_length = sizeof(rsp);
1567 int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
1568 TPM_DURATION_TYPE_SHORT);
1569 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1570 ret = -1;
1571
1572 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
1573 ret);
1574
1575 return ret;
1576}
1577
1578static int
1579tpm20_clear(void)
1580{
1581 struct tpm2_req_clear trq = {
1582 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1583 .hdr.totlen = cpu_to_be32(sizeof(trq)),
1584 .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
1585 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1586 .authblocksize = cpu_to_be32(sizeof(trq.authblock)),
1587 .authblock = {
1588 .handle = cpu_to_be32(TPM2_RS_PW),
1589 .noncesize = cpu_to_be16(0),
1590 .contsession = TPM2_YES,
1591 .pwdsize = cpu_to_be16(0),
1592 },
1593 };
1594 struct tpm_rsp_header rsp;
1595 u32 resp_length = sizeof(rsp);
1596 int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
1597 TPM_DURATION_TYPE_MEDIUM);
1598 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1599 ret = -1;
1600
1601 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
1602 ret);
1603
1604 return ret;
1605}
1606
1607static int
1608tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
1609{
1610 int ret = 0;
1611
1612 switch (msgCode) {
1613 case TPM_PPI_OP_NOOP: /* no-op */
1614 break;
1615
1616 case TPM_PPI_OP_CLEAR:
1617 ret = tpm20_clearcontrol(0, verbose);
1618 if (!ret)
1619 ret = tpm20_clear();
1620 break;
1621 }
1622
1623 if (ret)
1624 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
1625
1626 return ret;
1627}
1628
1629static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001630tpm12_get_tpm_state(void)
Stefan Berger320df852015-11-30 11:14:19 -05001631{
1632 int state = 0;
1633 struct tpm_permanent_flags pf;
1634 int has_owner;
1635
Stefan Berger1d37d522016-02-02 13:09:11 -05001636 if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) ||
1637 tpm12_read_has_owner(&has_owner))
Stefan Berger320df852015-11-30 11:14:19 -05001638 return ~0;
1639
1640 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1641 state |= TPM_STATE_ENABLED;
1642
1643 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1644 state |= TPM_STATE_ACTIVE;
1645
1646 if (has_owner) {
1647 state |= TPM_STATE_OWNED;
1648 } else {
1649 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1650 state |= TPM_STATE_OWNERINSTALL;
1651 }
1652
1653 return state;
1654}
1655
1656static void
Stefan Berger1d37d522016-02-02 13:09:11 -05001657tpm12_show_tpm_menu(int state, int next_scancodes[7])
Stefan Berger320df852015-11-30 11:14:19 -05001658{
1659 int i = 0;
1660
1661 printf("\nThe current state of the TPM is:\n");
1662
1663 if (state & TPM_STATE_ENABLED)
1664 printf(" Enabled");
1665 else
1666 printf(" Disabled");
1667
1668 if (state & TPM_STATE_ACTIVE)
1669 printf(" and active\n");
1670 else
1671 printf(" and deactivated\n");
1672
1673 if (state & TPM_STATE_OWNED)
1674 printf(" Ownership has been taken\n");
1675 else {
1676 printf(" Ownership has not been taken\n");
1677 if (state & TPM_STATE_OWNERINSTALL)
1678 printf(" A user can take ownership of the TPM\n");
1679 else
1680 printf(" Taking ownership of the TPM has been disabled\n");
1681 }
1682
1683 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1684 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1685 printf("\nNote: To make use of all functionality, the TPM must be "
1686 "enabled and active.\n");
1687 }
1688
1689 printf("\nAvailable options are:\n");
1690 if (state & TPM_STATE_ENABLED) {
1691 printf(" d. Disable the TPM\n");
1692 next_scancodes[i++] = 32;
1693
1694 if (state & TPM_STATE_ACTIVE) {
1695 printf(" v. Deactivate the TPM\n");
1696 next_scancodes[i++] = 47;
1697
1698 if (state & TPM_STATE_OWNERINSTALL) {
1699 printf(" p. Prevent installation of an owner\n");
1700 next_scancodes[i++] = 25;
1701 } else {
1702 printf(" s. Allow installation of an owner\n");
1703 next_scancodes[i++] = 31;
1704 }
1705 } else {
1706 printf(" a. Activate the TPM\n");
1707 next_scancodes[i++] = 30;
1708 }
1709
1710 } else {
1711 printf(" e. Enable the TPM\n");
1712 next_scancodes[i++] = 18;
1713 }
1714
1715 if (state & TPM_STATE_OWNED) {
1716 printf(" c. Clear ownership\n");
1717 next_scancodes[i++] = 46;
1718 }
1719
1720 next_scancodes[i++] = 0;
1721}
1722
Stefan Berger1d37d522016-02-02 13:09:11 -05001723static void
1724tpm12_menu(void)
Stefan Berger320df852015-11-30 11:14:19 -05001725{
Stefan Berger320df852015-11-30 11:14:19 -05001726 int scancode, next_scancodes[7];
Stefan Berger320df852015-11-30 11:14:19 -05001727 tpm_ppi_code msgCode;
1728 int state = 0, i;
1729 int waitkey;
1730
Stefan Berger320df852015-11-30 11:14:19 -05001731 printf("The Trusted Platform Module (TPM) is a hardware device in "
1732 "this machine.\n"
1733 "It can help verify the integrity of system software.\n\n");
1734
1735 for (;;) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001736 if ((state = tpm12_get_tpm_state()) != ~0) {
1737 tpm12_show_tpm_menu(state, next_scancodes);
Stefan Berger320df852015-11-30 11:14:19 -05001738 } else {
1739 printf("TPM is not working correctly.\n");
1740 return;
1741 }
1742
1743 printf("\nIf no change is desired or if this menu was reached by "
1744 "mistake, press ESC to\n"
1745 "reboot the machine.\n");
1746
1747 msgCode = TPM_PPI_OP_NOOP;
1748
1749 waitkey = 1;
1750
1751 while (waitkey) {
1752 while ((scancode = get_keystroke(1000)) == ~0)
1753 ;
1754
1755 switch (scancode) {
1756 case 1:
1757 // ESC
1758 reset();
1759 break;
1760 case 18: /* e. enable */
1761 msgCode = TPM_PPI_OP_ENABLE;
1762 break;
1763 case 32: /* d. disable */
1764 msgCode = TPM_PPI_OP_DISABLE;
1765 break;
1766 case 30: /* a. activate */
1767 msgCode = TPM_PPI_OP_ACTIVATE;
1768 break;
1769 case 47: /* v. deactivate */
1770 msgCode = TPM_PPI_OP_DEACTIVATE;
1771 break;
1772 case 46: /* c. clear owner */
1773 msgCode = TPM_PPI_OP_CLEAR;
1774 break;
1775 case 25: /* p. prevent ownerinstall */
1776 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1777 break;
1778 case 31: /* s. allow ownerinstall */
1779 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1780 break;
1781 default:
1782 continue;
1783 }
1784
1785 /*
1786 * Using the next_scancodes array, check whether the
1787 * pressed key is currently a valid option.
1788 */
1789 for (i = 0; i < sizeof(next_scancodes); i++) {
1790 if (next_scancodes[i] == 0)
1791 break;
1792
1793 if (next_scancodes[i] == scancode) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001794 tpm12_process_cfg(msgCode, 1);
Stefan Berger320df852015-11-30 11:14:19 -05001795 waitkey = 0;
1796 break;
1797 }
1798 }
1799 }
1800 }
1801}
Stefan Berger1d37d522016-02-02 13:09:11 -05001802
Stefan Berger7d596dc2016-02-02 13:09:16 -05001803static void
1804tpm20_menu(void)
1805{
1806 int scan_code;
1807 tpm_ppi_code msgCode;
1808
1809 for (;;) {
1810 printf("1. Clear TPM\n");
1811
1812 printf("\nIf no change is desired or if this menu was reached by "
1813 "mistake, press ESC to\n"
1814 "reboot the machine.\n");
1815
1816 msgCode = TPM_PPI_OP_NOOP;
1817
1818 while ((scan_code = get_keystroke(1000)) == ~0)
1819 ;
1820
1821 switch (scan_code) {
1822 case 1:
1823 // ESC
1824 reset();
1825 break;
1826 case 2:
1827 msgCode = TPM_PPI_OP_CLEAR;
1828 break;
1829 default:
1830 continue;
1831 }
1832
1833 tpm20_process_cfg(msgCode, 0);
1834 }
1835}
1836
Stefan Berger1d37d522016-02-02 13:09:11 -05001837void
1838tpm_menu(void)
1839{
1840 if (!CONFIG_TCGBIOS)
1841 return;
1842
1843 while (get_keystroke(0) >= 0)
1844 ;
1845 wait_threads();
1846
1847 switch (TPM_version) {
1848 case TPM_VERSION_1_2:
1849 tpm12_menu();
1850 break;
1851 case TPM_VERSION_2:
Stefan Berger7d596dc2016-02-02 13:09:16 -05001852 tpm20_menu();
Stefan Berger1d37d522016-02-02 13:09:11 -05001853 break;
1854 }
1855}