blob: 88652fecd6dc5aaac9dbd5b3a98b45b0da8c5634 [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 Bergerb310dfa2015-03-23 14:22:16 -040026
Stefan Berger0d289b52015-06-09 19:56:29 -040027static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
28static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040029
Stefan Berger0d289b52015-06-09 19:56:29 -040030static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
31static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
32static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
33static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040034
35static const u8 CommandFlag_FALSE[1] = { 0x00 };
36static const u8 CommandFlag_TRUE[1] = { 0x01 };
37
Stefan Berger0d289b52015-06-09 19:56:29 -040038static const u8 GetCapability_Permanent_Flags[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040039 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
40 0x00, 0x00, 0x01, 0x08
41};
42
Stefan Berger0d289b52015-06-09 19:56:29 -040043static const u8 GetCapability_OwnerAuth[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040044 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
45 0x00, 0x00, 0x01, 0x11
46};
47
48static const u8 GetCapability_Timeouts[] = {
49 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
50 0x00, 0x00, 0x01, 0x15
51};
52
53static const u8 GetCapability_Durations[] = {
54 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
55 0x00, 0x00, 0x01, 0x20
56};
57
Stefan Berger2aff1c12015-05-26 15:48:33 -040058static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
59
Stefan Bergerb310dfa2015-03-23 14:22:16 -040060
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050061/****************************************************************
62 * TPM state tracking
63 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040064
65typedef struct {
66 u8 tpm_probed:1;
67 u8 tpm_found:1;
68 u8 tpm_working:1;
69 u8 if_shutdown:1;
70 u8 tpm_driver_to_use:4;
Stefan Berger60bb9e92015-11-21 14:54:42 -050071 struct tcpa_descriptor_rev2 *tcpa;
72
73 /* length of the TCPA log buffer */
74 u32 log_area_minimum_length;
75
76 /* start address of TCPA log buffer */
77 u8 * log_area_start_address;
78
79 /* number of log entries written */
80 u32 entry_count;
81
82 /* address to write next log entry to */
83 u8 * log_area_next_entry;
84
85 /* address of last entry written (need for TCG_StatusCheck) */
86 u8 * log_area_last_entry;
Stefan Bergerb310dfa2015-03-23 14:22:16 -040087} tpm_state_t;
88
Stefan Berger60bb9e92015-11-21 14:54:42 -050089tpm_state_t tpm_state VARLOW = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040090 .tpm_driver_to_use = TPM_INVALID_DRIVER,
91};
92
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050093static u32
94is_preboot_if_shutdown(void)
95{
96 return tpm_state.if_shutdown;
97}
Stefan Bergerb310dfa2015-03-23 14:22:16 -040098
Stefan Bergerb310dfa2015-03-23 14:22:16 -040099
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500100/****************************************************************
101 * TPM hardware interface
102 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400103
104static u32
105is_tpm_present(void)
106{
107 u32 rc = 0;
108 unsigned int i;
109
110 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
111 struct tpm_driver *td = &tpm_drivers[i];
112 if (td->probe() != 0) {
113 td->init();
114 tpm_state.tpm_driver_to_use = i;
115 rc = 1;
116 break;
117 }
118 }
119
120 return rc;
121}
122
123static void
124probe_tpm(void)
125{
126 if (!tpm_state.tpm_probed) {
127 tpm_state.tpm_probed = 1;
128 tpm_state.tpm_found = (is_tpm_present() != 0);
129 tpm_state.tpm_working = tpm_state.tpm_found;
130 }
131}
132
133static int
134has_working_tpm(void)
135{
136 probe_tpm();
137
138 return tpm_state.tpm_working;
139}
140
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400141static u32
142transmit(u8 locty, const struct iovec iovec[],
143 u8 *respbuffer, u32 *respbufferlen,
144 enum tpmDurationType to_t)
145{
146 u32 rc = 0;
147 u32 irc;
148 struct tpm_driver *td;
149 unsigned int i;
150
151 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
152 return TCG_FATAL_COM_ERROR;
153
154 td = &tpm_drivers[tpm_state.tpm_driver_to_use];
155
156 irc = td->activate(locty);
157 if (irc != 0) {
158 /* tpm could not be activated */
159 return TCG_FATAL_COM_ERROR;
160 }
161
162 for (i = 0; iovec[i].length; i++) {
163 irc = td->senddata(iovec[i].data,
164 iovec[i].length);
165 if (irc != 0)
166 return TCG_FATAL_COM_ERROR;
167 }
168
169 irc = td->waitdatavalid();
170 if (irc != 0)
171 return TCG_FATAL_COM_ERROR;
172
173 irc = td->waitrespready(to_t);
174 if (irc != 0)
175 return TCG_FATAL_COM_ERROR;
176
177 irc = td->readresp(respbuffer,
178 respbufferlen);
179 if (irc != 0)
180 return TCG_FATAL_COM_ERROR;
181
182 td->ready();
183
184 return rc;
185}
186
187
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500188/****************************************************************
189 * ACPI TCPA table interface
190 ****************************************************************/
191
192static struct tcpa_descriptor_rev2 *
193find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
194{
195 u32 ctr = 0;
196 struct tcpa_descriptor_rev2 *tcpa = NULL;
197 struct rsdt_descriptor *rsdt;
198 u32 length;
199 u16 off;
200
201 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
202 if (!rsdt)
203 return NULL;
204
205 length = rsdt->length;
206 off = offsetof(struct rsdt_descriptor, entry);
207
208 while ((off + sizeof(rsdt->entry[0])) <= length) {
209 /* try all pointers to structures */
210 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
211
212 /* valid TCPA ACPI table ? */
213 if (tcpa->signature == TCPA_SIGNATURE &&
214 checksum((u8 *)tcpa, tcpa->length) == 0)
215 break;
216
217 tcpa = NULL;
218 off += sizeof(rsdt->entry[0]);
219 ctr++;
220 }
221
222 /* cache it */
223 if (tcpa)
224 tpm_state.tcpa = tcpa;
225
226 return tcpa;
227}
228
229static struct tcpa_descriptor_rev2 *
230find_tcpa_table(void)
231{
232 struct tcpa_descriptor_rev2 *tcpa = NULL;
233 struct rsdp_descriptor *rsdp = RsdpAddr;
234
235 if (tpm_state.tcpa)
236 return tpm_state.tcpa;
237
238 if (rsdp)
239 tcpa = find_tcpa_by_rsdp(rsdp);
240 else
241 tpm_state.if_shutdown = 1;
242
243 if (!rsdp)
244 dprintf(DEBUG_tcg,
245 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
246 else if (!tcpa)
247 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
248
249 return tcpa;
250}
251
252static u8 *
253get_lasa_base_ptr(u32 *log_area_minimum_length)
254{
255 u8 *log_area_start_address = 0;
256 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
257
258 if (tcpa) {
259 log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
260 if (log_area_minimum_length)
261 *log_area_minimum_length = tcpa->log_area_minimum_length;
262 }
263
264 return log_area_start_address;
265}
266
267/* clear the ACPI log */
268static void
269reset_acpi_log(void)
270{
271 tpm_state.log_area_start_address =
272 get_lasa_base_ptr(&tpm_state.log_area_minimum_length);
273
274 if (tpm_state.log_area_start_address)
275 memset(tpm_state.log_area_start_address, 0,
276 tpm_state.log_area_minimum_length);
277
278 tpm_state.log_area_next_entry = tpm_state.log_area_start_address;
279 tpm_state.log_area_last_entry = NULL;
280 tpm_state.entry_count = 0;
281}
282
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500283/*
284 * Extend the ACPI log with the given entry by copying the
285 * entry data into the log.
286 * Input
287 * pcpes : Pointer to the event 'header' to be copied into the log
288 * event : Pointer to the event 'body' to be copied into the log
289 * event_length: Length of the event array
290 * entry_count : optional pointer to get the current entry count
291 *
292 * Output:
293 * Returns an error code in case of faiure, 0 in case of success
294 */
295static u32
296tpm_extend_acpi_log(struct pcpes *pcpes,
297 const char *event, u32 event_length,
298 u16 *entry_count)
299{
300 u32 size;
301
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500302 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
303 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
304
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500305 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500306 return TCG_PC_LOGOVERFLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500307
308 size = offsetof(struct pcpes, event) + event_length;
309
310 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
311 tpm_state.log_area_minimum_length) {
312 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500313 return TCG_PC_LOGOVERFLOW;
314 }
315
316 pcpes->eventdatasize = event_length;
317
318 memcpy(tpm_state.log_area_next_entry, pcpes, offsetof(struct pcpes, event));
319 memcpy(tpm_state.log_area_next_entry + offsetof(struct pcpes, event),
320 event, event_length);
321
322 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
323 tpm_state.log_area_next_entry += size;
324 tpm_state.entry_count++;
325
326 if (entry_count)
327 *entry_count = tpm_state.entry_count;
328
329 return 0;
330}
331
332
333/****************************************************************
334 * Helper functions
335 ****************************************************************/
336
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400337/*
338 * Send a TPM command with the given ordinal. Append the given buffer
339 * containing all data in network byte order to the command (this is
340 * the custom part per command) and expect a response of the given size.
341 * If a buffer is provided, the response will be copied into it.
342 */
343static u32
Stefan Berger47b9df52015-11-21 14:54:40 -0500344build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
345 u8 *resbuffer, u32 return_size, u32 *returnCode,
346 enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400347{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400348 u32 rc;
Stefan Bergerece25612015-11-12 10:14:46 -0500349 u8 obuffer[64];
350 struct tpm_req_header trqh;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400351 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Berger47b9df52015-11-21 14:54:40 -0500352 struct iovec iovec[3] = {{ 0 }};
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400353 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400354
Stefan Bergerece25612015-11-12 10:14:46 -0500355 if (return_size > sizeof(obuffer)) {
356 dprintf(DEBUG_tcg, "TCGBIOS: size of requested response too big.");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400357 return TCG_FIRMWARE_ERROR;
358 }
359
Stefan Bergerece25612015-11-12 10:14:46 -0500360 trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
Stefan Berger47b9df52015-11-21 14:54:40 -0500361 trqh.totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size);
Stefan Bergerece25612015-11-12 10:14:46 -0500362 trqh.ordinal = cpu_to_be32(ordinal);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400363
Stefan Bergerece25612015-11-12 10:14:46 -0500364 iovec[0].data = &trqh;
365 iovec[0].length = TPM_REQ_HEADER_SIZE;
366
367 if (append_size) {
368 iovec[1].data = append;
369 iovec[1].length = append_size;
Stefan Bergerece25612015-11-12 10:14:46 -0500370 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400371
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400372 memset(obuffer, 0x0, sizeof(obuffer));
373
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400374 rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
375 if (rc)
376 return rc;
377
378 *returnCode = be32_to_cpu(trsh->errcode);
379
380 if (resbuffer)
381 memcpy(resbuffer, trsh, return_size);
382
383 return 0;
384}
385
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500386static void
387tpm_set_failure(void)
388{
389 u32 returnCode;
390
391 /* we will try to deactivate the TPM now - ignoring all errors */
392 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
393 PhysicalPresence_CMD_ENABLE,
394 sizeof(PhysicalPresence_CMD_ENABLE),
395 NULL, 0, &returnCode,
396 TPM_DURATION_TYPE_SHORT);
397
398 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
399 PhysicalPresence_PRESENT,
400 sizeof(PhysicalPresence_PRESENT),
401 NULL, 0, &returnCode,
402 TPM_DURATION_TYPE_SHORT);
403
404 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
405 NULL, 0, NULL, 0, &returnCode,
406 TPM_DURATION_TYPE_SHORT);
407
408 tpm_state.tpm_working = 0;
409}
410
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400411static u32
412determine_timeouts(void)
413{
414 u32 rc;
415 u32 returnCode;
416 struct tpm_res_getcap_timeouts timeouts;
417 struct tpm_res_getcap_durations durations;
418 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
419 u32 i;
420
Stefan Berger5aa2a752015-03-23 14:22:17 -0400421 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400422 GetCapability_Timeouts,
423 sizeof(GetCapability_Timeouts),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400424 (u8 *)&timeouts, sizeof(timeouts),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400425 &returnCode, TPM_DURATION_TYPE_SHORT);
426
427 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
428 " = 0x%08x\n", returnCode);
429
430 if (rc || returnCode)
431 goto err_exit;
432
Stefan Berger5aa2a752015-03-23 14:22:17 -0400433 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400434 GetCapability_Durations,
435 sizeof(GetCapability_Durations),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400436 (u8 *)&durations, sizeof(durations),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400437 &returnCode, TPM_DURATION_TYPE_SHORT);
438
439 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
440 " = 0x%08x\n", returnCode);
441
442 if (rc || returnCode)
443 goto err_exit;
444
445 for (i = 0; i < 3; i++)
446 durations.durations[i] = be32_to_cpu(durations.durations[i]);
447
448 for (i = 0; i < 4; i++)
449 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
450
451 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
452 timeouts.timeouts[0],
453 timeouts.timeouts[1],
454 timeouts.timeouts[2],
455 timeouts.timeouts[3]);
456
457 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
458 durations.durations[0],
459 durations.durations[1],
460 durations.durations[2]);
461
462
463 td->set_timeouts(timeouts.timeouts, durations.durations);
464
465 return 0;
466
467err_exit:
468 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
469
Stefan Berger7fce1d92015-11-12 10:14:45 -0500470 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400471 if (rc)
472 return rc;
473 return TCG_TCG_COMMAND_ERROR;
474}
475
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500476static u32
477pass_through_to_tpm(u8 locty, const u8 *cmd, u32 cmd_length,
478 u8 *resp, u32 *resp_length)
479{
480 struct iovec iovec[2] = {{ 0 }};
481 const u32 *tmp;
482
483 if (cmd_length < TPM_REQ_HEADER_SIZE)
484 return TCG_INVALID_INPUT_PARA;
485
486 iovec[0].data = cmd;
487 tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
488 iovec[0].length = cpu_to_be32(*tmp);
489
490 if (cmd_length != iovec[0].length)
491 return TCG_INVALID_INPUT_PARA;
492
493 return transmit(locty, iovec, resp, resp_length,
494 TPM_DURATION_TYPE_LONG /* worst case */);
495
496}
497
498static u32
499tpm_extend(u8 *hash, u32 pcrindex)
500{
501 u32 rc;
502 struct tpm_req_extend tre = {
503 .tag = cpu_to_be16(TPM_TAG_RQU_CMD),
504 .totlen = cpu_to_be32(sizeof(tre)),
505 .ordinal = cpu_to_be32(TPM_ORD_Extend),
506 .pcrindex = cpu_to_be32(pcrindex),
507 };
508 struct tpm_rsp_extend rsp;
509 u32 resp_length = sizeof(rsp);
510
511 memcpy(tre.digest, hash, sizeof(tre.digest));
512
513 rc = pass_through_to_tpm(0, (u8 *)&tre, sizeof(tre),
514 (u8 *)&rsp, &resp_length);
515
516 if (rc || resp_length != sizeof(rsp))
517 tpm_set_failure();
518
519 return rc;
520}
521
522static u32
523hash_log_event(const void *hashdata, u32 hashdata_length,
524 struct pcpes *pcpes,
525 const char *event, u32 event_length,
526 u16 *entry_count)
527{
528 u32 rc = 0;
529
530 if (pcpes->pcrindex >= 24)
531 return TCG_INVALID_INPUT_PARA;
532
533 if (hashdata) {
534 rc = sha1(hashdata, hashdata_length, pcpes->digest);
535 if (rc)
536 return rc;
537 }
538
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500539 if (!has_working_tpm())
540 return TCG_GENERAL_ERROR;
541
542 rc = tpm_extend_acpi_log(pcpes, event, event_length, entry_count);
543 if (rc)
544 tpm_set_failure();
545 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500546}
547
548static u32
549hash_log_extend_event(const void *hashdata, u32 hashdata_length,
550 struct pcpes *pcpes,
551 const char *event, u32 event_length,
552 u32 pcrindex, u16 *entry_count)
553{
554 u32 rc;
555
556 rc = hash_log_event(hashdata, hashdata_length, pcpes,
557 event, event_length, entry_count);
558 if (rc)
559 return rc;
560
561 return tpm_extend(pcpes->digest, pcrindex);
562}
563
564/*
565 * Add a measurement to the log; the data at data_seg:data/length are
566 * appended to the TCG_PCClientPCREventStruct
567 *
568 * Input parameters:
569 * pcrindex : which PCR to extend
570 * event_type : type of event; specs section on 'Event Types'
571 * event : pointer to info (e.g., string) to be added to log as-is
572 * event_length: length of the event
573 * hashdata : pointer to the data to be hashed
574 * hashdata_length: length of the data to be hashed
575 */
576static u32
577tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
578 const char *event, u32 event_length,
579 const u8 *hashdata, u32 hashdata_length)
580{
581 struct pcpes pcpes = {
582 .pcrindex = pcrindex,
583 .eventtype = event_type,
584 };
585 u16 entry_count;
586
587 return hash_log_extend_event(hashdata, hashdata_length, &pcpes,
588 event, event_length, pcrindex,
589 &entry_count);
590}
591
592
593/****************************************************************
594 * Setup and Measurements
595 ****************************************************************/
596
597/*
598 * Add a measurement to the list of measurements
599 * pcrIndex : PCR to be extended
600 * event_type : type of event; specs section on 'Event Types'
601 * data : additional parameter; used as parameter for
602 * 'action index'
603 */
604static u32
605tpm_add_measurement(u32 pcrIndex,
606 u16 event_type,
607 const char *string)
608{
609 u32 rc;
610 u32 len;
611
612 switch (event_type) {
613 case EV_SEPARATOR:
614 len = sizeof(evt_separator);
615 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
616 (char *)NULL, 0,
617 (u8 *)evt_separator, len);
618 break;
619
620 case EV_ACTION:
621 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
622 string, strlen(string),
623 (u8 *)string, strlen(string));
624 break;
625
626 default:
627 rc = TCG_INVALID_INPUT_PARA;
628 }
629
630 return rc;
631}
632
633static u32
634tpm_calling_int19h(void)
635{
636 if (!CONFIG_TCGBIOS)
637 return 0;
638
639 if (!has_working_tpm())
640 return TCG_GENERAL_ERROR;
641
642 return tpm_add_measurement(4, EV_ACTION,
643 "Calling INT 19h");
644}
645
646/*
647 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
648 */
649static u32
650tpm_add_event_separators(void)
651{
652 u32 rc;
653 u32 pcrIndex = 0;
654
655 if (!CONFIG_TCGBIOS)
656 return 0;
657
658 if (!has_working_tpm())
659 return TCG_GENERAL_ERROR;
660
661 while (pcrIndex <= 7) {
662 rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
663 if (rc)
664 break;
665 pcrIndex ++;
666 }
667
668 return rc;
669}
670
671/*
672 * Add measurement to the log about option rom scan
673 */
674static u32
675tpm_start_option_rom_scan(void)
676{
677 if (!CONFIG_TCGBIOS)
678 return 0;
679
680 if (!has_working_tpm())
681 return TCG_GENERAL_ERROR;
682
683 return tpm_add_measurement(2, EV_ACTION,
684 "Start Option ROM Scan");
685}
686
687static u32
688tpm_smbios_measure(void)
689{
690 if (!CONFIG_TCGBIOS)
691 return 0;
692
693 if (!has_working_tpm())
694 return TCG_GENERAL_ERROR;
695
696 u32 rc;
697 struct pcctes pcctes = {
698 .eventid = 1,
699 .eventdatasize = SHA1_BUFSIZE,
700 };
701 struct smbios_entry_point *sep = SMBiosAddr;
702
703 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
704
705 if (!sep)
706 return 0;
707
708 rc = sha1((const u8 *)sep->structure_table_address,
709 sep->structure_table_length, pcctes.digest);
710 if (rc)
711 return rc;
712
713 return tpm_add_measurement_to_log(1,
714 EV_EVENT_TAG,
715 (const char *)&pcctes, sizeof(pcctes),
716 (u8 *)&pcctes, sizeof(pcctes));
717}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400718
719static u32
720tpm_startup(void)
721{
722 u32 rc;
723 u32 returnCode;
724
725 if (!has_working_tpm())
726 return TCG_GENERAL_ERROR;
727
728 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400729 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400730 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400731 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400732
733 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
734 returnCode);
735
736 if (CONFIG_COREBOOT) {
737 /* with other firmware on the system the TPM may already have been
738 * initialized
739 */
740 if (returnCode == TPM_INVALID_POSTINIT)
741 returnCode = 0;
742 }
743
744 if (rc || returnCode)
745 goto err_exit;
746
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500747 rc = determine_timeouts();
748 if (rc)
749 goto err_exit;
750
Stefan Berger5aa2a752015-03-23 14:22:17 -0400751 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400752 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400753
754 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
755 returnCode);
756
757 if (rc || returnCode)
758 goto err_exit;
759
Stefan Berger5aa2a752015-03-23 14:22:17 -0400760 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400761 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400762
763 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
764 returnCode);
765
766 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
767 goto err_exit;
768
Stefan Berger2aff1c12015-05-26 15:48:33 -0400769 rc = tpm_smbios_measure();
770 if (rc)
771 goto err_exit;
772
773 rc = tpm_start_option_rom_scan();
774 if (rc)
775 goto err_exit;
776
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400777 return 0;
778
779err_exit:
780 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
781
Stefan Berger7fce1d92015-11-12 10:14:45 -0500782 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400783 if (rc)
784 return rc;
785 return TCG_TCG_COMMAND_ERROR;
786}
787
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500788/*
789 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
790 where the TCPA table is.
791 */
792static void
793tpm_acpi_init(void)
794{
795 tpm_state.if_shutdown = 0;
796 tpm_state.tpm_probed = 0;
797 tpm_state.tpm_found = 0;
798 tpm_state.tpm_working = 0;
799
800 if (!has_working_tpm()) {
801 tpm_state.if_shutdown = 1;
802 return;
803 }
804
805 reset_acpi_log();
806}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400807
Kevin O'Connord6aca442015-06-10 11:00:17 -0400808void
809tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400810{
811 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400812 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400813
814 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400815 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400816 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400817
Kevin O'Connord6aca442015-06-10 11:00:17 -0400818 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400819}
820
Kevin O'Connord6aca442015-06-10 11:00:17 -0400821void
822tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400823{
824 u32 rc;
825 u32 returnCode;
826
827 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400828 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400829
830 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400831 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400832
Stefan Berger5aa2a752015-03-23 14:22:17 -0400833 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400834 PhysicalPresence_CMD_ENABLE,
835 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400836 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400837 if (rc || returnCode)
838 goto err_exit;
839
Stefan Berger5aa2a752015-03-23 14:22:17 -0400840 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400841 PhysicalPresence_NOT_PRESENT_LOCK,
842 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400843 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400844 if (rc || returnCode)
845 goto err_exit;
846
Stefan Berger2aff1c12015-05-26 15:48:33 -0400847 rc = tpm_calling_int19h();
848 if (rc)
849 goto err_exit;
850
851 rc = tpm_add_event_separators();
852 if (rc)
853 goto err_exit;
854
Kevin O'Connord6aca442015-06-10 11:00:17 -0400855 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400856
857err_exit:
858 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
859
Stefan Berger7fce1d92015-11-12 10:14:45 -0500860 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400861}
862
Stefan Berger5aa2a752015-03-23 14:22:17 -0400863/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500864 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400865 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500866u32
867tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400868{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500869 if (!CONFIG_TCGBIOS)
870 return 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400871
Stefan Berger7fce1d92015-11-12 10:14:45 -0500872 if (!has_working_tpm())
873 return TCG_GENERAL_ERROR;
874
Stefan Berger5aa2a752015-03-23 14:22:17 -0400875 u32 rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500876 struct pcctes_romex pcctes = {
877 .eventid = 7,
878 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400879 };
880
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500881 rc = sha1((const u8 *)addr, len, pcctes.digest);
Stefan Berger6c376b42015-11-12 10:14:49 -0500882 if (rc)
883 return rc;
884
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500885 return tpm_add_measurement_to_log(2,
886 EV_EVENT_TAG,
887 (const char *)&pcctes, sizeof(pcctes),
888 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500889}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400890
Stefan Berger2aff1c12015-05-26 15:48:33 -0400891/*
892 * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
893 * the list of measurements.
894 */
895static u32
896tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
897{
898 const char *string;
899
900 if (!CONFIG_TCGBIOS)
901 return 0;
902
903 if (!has_working_tpm())
904 return TCG_GENERAL_ERROR;
905
906 switch (bootcd) {
907 case 0:
908 switch (bootdrv) {
909 case 0:
910 string = "Booting BCV device 00h (Floppy)";
911 break;
912
913 case 0x80:
914 string = "Booting BCV device 80h (HDD)";
915 break;
916
917 default:
918 string = "Booting unknown device";
919 break;
920 }
921
922 break;
923
924 default:
925 string = "Booting from CD ROM device";
926 }
927
928 return tpm_add_measurement_to_log(4, EV_ACTION,
929 string, strlen(string),
930 (u8 *)string, strlen(string));
931}
932
Stefan Berger2aff1c12015-05-26 15:48:33 -0400933/*
934 * Add a measurement related to Initial Program Loader to the log.
935 * Creates two log entries.
936 *
937 * Input parameter:
938 * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
939 * addr : address where the IP data are located
940 * length : IP data length in bytes
941 */
942static u32
943tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
944{
945 u32 rc;
946 const char *string;
947
948 switch (bootcd) {
949 case IPL_EL_TORITO_1:
950 /* specs: see section 'El Torito' */
951 string = "EL TORITO IPL";
952 rc = tpm_add_measurement_to_log(4, EV_IPL,
953 string, strlen(string),
954 addr, length);
955 break;
956
957 case IPL_EL_TORITO_2:
958 /* specs: see section 'El Torito' */
959 string = "BOOT CATALOG";
960 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
961 string, strlen(string),
962 addr, length);
963 break;
964
965 default:
966 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
967 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
968 string = "MBR";
969 rc = tpm_add_measurement_to_log(4, EV_IPL,
970 string, strlen(string),
971 addr, 0x1b8);
972
973 if (rc)
974 break;
975
976 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
977 string = "MBR PARTITION_TABLE";
978 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
979 string, strlen(string),
980 addr + 0x1b8, 0x48);
981 }
982
983 return rc;
984}
985
986u32
987tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
988{
989 if (!CONFIG_TCGBIOS)
990 return 0;
991
992 if (!has_working_tpm())
993 return TCG_GENERAL_ERROR;
994
995 u32 rc = tpm_add_bootdevice(0, bootdrv);
996 if (rc)
997 return rc;
998
999 return tpm_ipl(IPL_BCV, addr, length);
1000}
1001
1002u32
1003tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1004{
1005 if (!CONFIG_TCGBIOS)
1006 return 0;
1007
1008 if (!has_working_tpm())
1009 return TCG_GENERAL_ERROR;
1010
1011 u32 rc = tpm_add_bootdevice(1, bootdrv);
1012 if (rc)
1013 return rc;
1014
1015 return tpm_ipl(IPL_EL_TORITO_1, addr, length);
1016}
1017
1018u32
1019tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1020{
1021 if (!CONFIG_TCGBIOS)
1022 return 0;
1023
1024 if (!has_working_tpm())
1025 return TCG_GENERAL_ERROR;
1026
1027 u32 rc = tpm_add_bootdevice(1, 0);
1028 if (rc)
1029 return rc;
1030
1031 return tpm_ipl(IPL_EL_TORITO_2, addr, length);
1032}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001033
Kevin O'Connord6aca442015-06-10 11:00:17 -04001034void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001035tpm_s3_resume(void)
1036{
1037 u32 rc;
1038 u32 returnCode;
1039
1040 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001041 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001042
1043 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001044 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001045
1046 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1047
Stefan Berger5aa2a752015-03-23 14:22:17 -04001048 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001049 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -04001050 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001051
1052 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
1053 returnCode);
1054
1055 if (rc || returnCode)
1056 goto err_exit;
1057
Kevin O'Connord6aca442015-06-10 11:00:17 -04001058 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001059
1060err_exit:
1061 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1062
Stefan Berger7fce1d92015-11-12 10:14:45 -05001063 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001064}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001065
1066
1067/****************************************************************
1068 * BIOS interface
1069 ****************************************************************/
1070
1071static inline void *input_buf32(struct bregs *regs)
1072{
1073 return MAKE_FLATPTR(regs->es, regs->di);
1074}
1075
1076static inline void *output_buf32(struct bregs *regs)
1077{
1078 return MAKE_FLATPTR(regs->ds, regs->si);
1079}
1080
1081static u32
1082hash_log_extend_event_int(const struct hleei_short *hleei_s,
1083 struct hleeo *hleeo)
1084{
1085 u32 rc = 0;
1086 struct hleo hleo;
1087 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
1088 const void *logdataptr;
1089 u32 logdatalen;
1090 struct pcpes *pcpes;
1091 u32 pcrindex;
1092
1093 if (is_preboot_if_shutdown() != 0) {
1094 rc = TCG_INTERFACE_SHUTDOWN;
1095 goto err_exit;
1096 }
1097
1098 /* short or long version? */
1099 switch (hleei_s->ipblength) {
1100 case sizeof(struct hleei_short):
1101 /* short */
1102 logdataptr = hleei_s->logdataptr;
1103 logdatalen = hleei_s->logdatalen;
1104 pcrindex = hleei_s->pcrindex;
1105 break;
1106
1107 case sizeof(struct hleei_long):
1108 /* long */
1109 logdataptr = hleei_l->logdataptr;
1110 logdatalen = hleei_l->logdatalen;
1111 pcrindex = hleei_l->pcrindex;
1112 break;
1113
1114 default:
1115 /* bad input block */
1116 rc = TCG_INVALID_INPUT_PARA;
1117 goto err_exit;
1118 }
1119
1120 pcpes = (struct pcpes *)logdataptr;
1121
1122 if (pcpes->pcrindex >= 24 ||
1123 pcpes->pcrindex != pcrindex ||
1124 logdatalen != offsetof(struct pcpes, event) + pcpes->eventdatasize) {
1125 rc = TCG_INVALID_INPUT_PARA;
1126 goto err_exit;
1127 }
1128
1129 rc = hash_log_extend_event(hleei_s->hashdataptr, hleei_s->hashdatalen,
1130 pcpes,
1131 (char *)&pcpes->event, pcpes->eventdatasize,
1132 pcrindex, NULL);
1133 if (rc)
1134 goto err_exit;
1135
1136 hleeo->opblength = sizeof(struct hleeo);
1137 hleeo->reserved = 0;
1138 hleeo->eventnumber = hleo.eventnumber;
1139
1140err_exit:
1141 if (rc != 0) {
1142 hleeo->opblength = 4;
1143 hleeo->reserved = 0;
1144 }
1145
1146 return rc;
1147
1148}
1149
1150static u32
1151pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
1152{
1153 u32 rc = 0;
1154 u32 resbuflen = 0;
1155 struct tpm_req_header *trh;
1156
1157 if (is_preboot_if_shutdown()) {
1158 rc = TCG_INTERFACE_SHUTDOWN;
1159 goto err_exit;
1160 }
1161
1162 trh = (struct tpm_req_header *)pttti->tpmopin;
1163
1164 if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
1165 pttti->opblength < sizeof(struct pttto) ||
1166 be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) {
1167 rc = TCG_INVALID_INPUT_PARA;
1168 goto err_exit;
1169 }
1170
1171 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
1172
1173 rc = pass_through_to_tpm(0, pttti->tpmopin,
1174 pttti->ipblength - offsetof(struct pttti, tpmopin),
1175 pttto->tpmopout, &resbuflen);
1176
1177 if (rc)
1178 goto err_exit;
1179
1180 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
1181 pttto->reserved = 0;
1182
1183err_exit:
1184 if (rc != 0) {
1185 pttto->opblength = 4;
1186 pttto->reserved = 0;
1187 }
1188
1189 return rc;
1190}
1191
1192static u32
1193shutdown_preboot_interface(void)
1194{
1195 u32 rc = 0;
1196
1197 if (!is_preboot_if_shutdown()) {
1198 tpm_state.if_shutdown = 1;
1199 } else {
1200 rc = TCG_INTERFACE_SHUTDOWN;
1201 }
1202
1203 return rc;
1204}
1205
1206static u32
1207hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1208{
1209 u32 rc = 0;
1210 u16 size;
1211 struct pcpes *pcpes;
1212 u16 entry_count;
1213
1214 if (is_preboot_if_shutdown() != 0) {
1215 rc = TCG_INTERFACE_SHUTDOWN;
1216 goto err_exit;
1217 }
1218
1219 size = hlei->ipblength;
1220 if (size != sizeof(*hlei)) {
1221 rc = TCG_INVALID_INPUT_PARA;
1222 goto err_exit;
1223 }
1224
1225 pcpes = (struct pcpes *)hlei->logdataptr;
1226
1227 if (pcpes->pcrindex >= 24 ||
1228 pcpes->pcrindex != hlei->pcrindex ||
1229 pcpes->eventtype != hlei->logeventtype ||
1230 hlei->logdatalen !=
1231 offsetof(struct pcpes, event) + pcpes->eventdatasize) {
1232 rc = TCG_INVALID_INPUT_PARA;
1233 goto err_exit;
1234 }
1235
1236 rc = hash_log_event(hlei->hashdataptr, hlei->hashdatalen,
1237 pcpes, (char *)&pcpes->event, pcpes->eventdatasize,
1238 &entry_count);
1239 if (rc)
1240 goto err_exit;
1241
1242 /* updating the log was fine */
1243 hleo->opblength = sizeof(struct hleo);
1244 hleo->reserved = 0;
1245 hleo->eventnumber = entry_count;
1246
1247err_exit:
1248 if (rc != 0) {
1249 hleo->opblength = 2;
1250 hleo->reserved = 0;
1251 }
1252
1253 return rc;
1254}
1255
1256static u32
1257hash_all_int(const struct hai *hai, u8 *hash)
1258{
1259 if (is_preboot_if_shutdown() != 0)
1260 return TCG_INTERFACE_SHUTDOWN;
1261
1262 if (hai->ipblength != sizeof(struct hai) ||
1263 hai->hashdataptr == 0 ||
1264 hai->hashdatalen == 0 ||
1265 hai->algorithmid != TPM_ALG_SHA)
1266 return TCG_INVALID_INPUT_PARA;
1267
1268 return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1269}
1270
1271static u32
1272tss_int(struct ti *ti, struct to *to)
1273{
1274 u32 rc = 0;
1275
1276 if (is_preboot_if_shutdown() == 0) {
1277 rc = TCG_PC_UNSUPPORTED;
1278 } else {
1279 rc = TCG_INTERFACE_SHUTDOWN;
1280 }
1281
1282 to->opblength = sizeof(struct to);
1283 to->reserved = 0;
1284
1285 return rc;
1286}
1287
1288static u32
1289compact_hash_log_extend_event_int(u8 *buffer,
1290 u32 info,
1291 u32 length,
1292 u32 pcrindex,
1293 u32 *edx_ptr)
1294{
1295 u32 rc = 0;
1296 struct pcpes pcpes = {
1297 .pcrindex = pcrindex,
1298 .eventtype = EV_COMPACT_HASH,
1299 .eventdatasize = sizeof(info),
1300 .event = info,
1301 };
1302 u16 entry_count;
1303
1304 if (is_preboot_if_shutdown() != 0)
1305 return TCG_INTERFACE_SHUTDOWN;
1306
1307 rc = hash_log_extend_event(buffer, length,
1308 &pcpes,
1309 (char *)&pcpes.event, pcpes.eventdatasize,
1310 pcpes.pcrindex, &entry_count);
1311
1312 if (rc == 0)
1313 *edx_ptr = entry_count;
1314
1315 return rc;
1316}
1317
1318void VISIBLE32FLAT
1319tpm_interrupt_handler32(struct bregs *regs)
1320{
1321 if (!CONFIG_TCGBIOS)
1322 return;
1323
1324 set_cf(regs, 0);
1325
1326 if (!has_working_tpm()) {
1327 regs->eax = TCG_GENERAL_ERROR;
1328 return;
1329 }
1330
1331 switch ((enum irq_ids)regs->al) {
1332 case TCG_StatusCheck:
1333 if (is_tpm_present() == 0) {
1334 /* no TPM available */
1335 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1336 } else {
1337 regs->eax = 0;
1338 regs->ebx = TCG_MAGIC;
1339 regs->ch = TCG_VERSION_MAJOR;
1340 regs->cl = TCG_VERSION_MINOR;
1341 regs->edx = 0x0;
1342 regs->esi = (u32)tpm_state.log_area_start_address;
1343 regs->edi = (u32)tpm_state.log_area_last_entry;
1344 }
1345 break;
1346
1347 case TCG_HashLogExtendEvent:
1348 regs->eax =
1349 hash_log_extend_event_int(
1350 (struct hleei_short *)input_buf32(regs),
1351 (struct hleeo *)output_buf32(regs));
1352 break;
1353
1354 case TCG_PassThroughToTPM:
1355 regs->eax =
1356 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1357 (struct pttto *)output_buf32(regs));
1358 break;
1359
1360 case TCG_ShutdownPreBootInterface:
1361 regs->eax = shutdown_preboot_interface();
1362 break;
1363
1364 case TCG_HashLogEvent:
1365 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1366 (struct hleo*)output_buf32(regs));
1367 break;
1368
1369 case TCG_HashAll:
1370 regs->eax =
1371 hash_all_int((struct hai*)input_buf32(regs),
1372 (u8 *)output_buf32(regs));
1373 break;
1374
1375 case TCG_TSS:
1376 regs->eax = tss_int((struct ti*)input_buf32(regs),
1377 (struct to*)output_buf32(regs));
1378 break;
1379
1380 case TCG_CompactHashLogExtendEvent:
1381 regs->eax =
1382 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1383 regs->esi,
1384 regs->ecx,
1385 regs->edx,
1386 &regs->edx);
1387 break;
1388
1389 default:
1390 set_cf(regs, 1);
1391 }
1392
1393 return;
1394}