blob: e5cb9eb7cd89e1b5603d10b43e18f05d974fac47 [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
58
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050059/****************************************************************
60 * TPM state tracking
61 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040062
63typedef struct {
64 u8 tpm_probed:1;
65 u8 tpm_found:1;
66 u8 tpm_working:1;
67 u8 if_shutdown:1;
68 u8 tpm_driver_to_use:4;
Stefan Berger60bb9e92015-11-21 14:54:42 -050069 struct tcpa_descriptor_rev2 *tcpa;
70
71 /* length of the TCPA log buffer */
72 u32 log_area_minimum_length;
73
74 /* start address of TCPA log buffer */
75 u8 * log_area_start_address;
76
77 /* number of log entries written */
78 u32 entry_count;
79
80 /* address to write next log entry to */
81 u8 * log_area_next_entry;
82
83 /* address of last entry written (need for TCG_StatusCheck) */
84 u8 * log_area_last_entry;
Stefan Bergerb310dfa2015-03-23 14:22:16 -040085} tpm_state_t;
86
Stefan Berger60bb9e92015-11-21 14:54:42 -050087tpm_state_t tpm_state VARLOW = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040088 .tpm_driver_to_use = TPM_INVALID_DRIVER,
89};
90
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050091static u32
92is_preboot_if_shutdown(void)
93{
94 return tpm_state.if_shutdown;
95}
Stefan Bergerb310dfa2015-03-23 14:22:16 -040096
Stefan Bergerb310dfa2015-03-23 14:22:16 -040097
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050098/****************************************************************
99 * TPM hardware interface
100 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400101
102static u32
103is_tpm_present(void)
104{
105 u32 rc = 0;
106 unsigned int i;
107
108 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
109 struct tpm_driver *td = &tpm_drivers[i];
110 if (td->probe() != 0) {
111 td->init();
112 tpm_state.tpm_driver_to_use = i;
113 rc = 1;
114 break;
115 }
116 }
117
118 return rc;
119}
120
121static void
122probe_tpm(void)
123{
124 if (!tpm_state.tpm_probed) {
125 tpm_state.tpm_probed = 1;
126 tpm_state.tpm_found = (is_tpm_present() != 0);
127 tpm_state.tpm_working = tpm_state.tpm_found;
128 }
129}
130
131static int
132has_working_tpm(void)
133{
134 probe_tpm();
135
136 return tpm_state.tpm_working;
137}
138
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400139static u32
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500140transmit(u8 locty, struct tpm_req_header *req,
141 void *respbuffer, u32 *respbufferlen,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400142 enum tpmDurationType to_t)
143{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400144 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
145 return TCG_FATAL_COM_ERROR;
146
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500147 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400148
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500149 u32 irc = td->activate(locty);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400150 if (irc != 0) {
151 /* tpm could not be activated */
152 return TCG_FATAL_COM_ERROR;
153 }
154
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500155 irc = td->senddata((void*)req, be32_to_cpu(req->totlen));
156 if (irc != 0)
157 return TCG_FATAL_COM_ERROR;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400158
159 irc = td->waitdatavalid();
160 if (irc != 0)
161 return TCG_FATAL_COM_ERROR;
162
163 irc = td->waitrespready(to_t);
164 if (irc != 0)
165 return TCG_FATAL_COM_ERROR;
166
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500167 irc = td->readresp(respbuffer, respbufferlen);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400168 if (irc != 0)
169 return TCG_FATAL_COM_ERROR;
170
171 td->ready();
172
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500173 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400174}
175
176
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500177/****************************************************************
178 * ACPI TCPA table interface
179 ****************************************************************/
180
181static struct tcpa_descriptor_rev2 *
182find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
183{
184 u32 ctr = 0;
185 struct tcpa_descriptor_rev2 *tcpa = NULL;
186 struct rsdt_descriptor *rsdt;
187 u32 length;
188 u16 off;
189
190 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
191 if (!rsdt)
192 return NULL;
193
194 length = rsdt->length;
195 off = offsetof(struct rsdt_descriptor, entry);
196
197 while ((off + sizeof(rsdt->entry[0])) <= length) {
198 /* try all pointers to structures */
199 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
200
201 /* valid TCPA ACPI table ? */
202 if (tcpa->signature == TCPA_SIGNATURE &&
203 checksum((u8 *)tcpa, tcpa->length) == 0)
204 break;
205
206 tcpa = NULL;
207 off += sizeof(rsdt->entry[0]);
208 ctr++;
209 }
210
211 /* cache it */
212 if (tcpa)
213 tpm_state.tcpa = tcpa;
214
215 return tcpa;
216}
217
218static struct tcpa_descriptor_rev2 *
219find_tcpa_table(void)
220{
221 struct tcpa_descriptor_rev2 *tcpa = NULL;
222 struct rsdp_descriptor *rsdp = RsdpAddr;
223
224 if (tpm_state.tcpa)
225 return tpm_state.tcpa;
226
227 if (rsdp)
228 tcpa = find_tcpa_by_rsdp(rsdp);
229 else
230 tpm_state.if_shutdown = 1;
231
232 if (!rsdp)
233 dprintf(DEBUG_tcg,
234 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
235 else if (!tcpa)
236 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
237
238 return tcpa;
239}
240
241static u8 *
242get_lasa_base_ptr(u32 *log_area_minimum_length)
243{
244 u8 *log_area_start_address = 0;
245 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
246
247 if (tcpa) {
248 log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
249 if (log_area_minimum_length)
250 *log_area_minimum_length = tcpa->log_area_minimum_length;
251 }
252
253 return log_area_start_address;
254}
255
256/* clear the ACPI log */
257static void
258reset_acpi_log(void)
259{
260 tpm_state.log_area_start_address =
261 get_lasa_base_ptr(&tpm_state.log_area_minimum_length);
262
263 if (tpm_state.log_area_start_address)
264 memset(tpm_state.log_area_start_address, 0,
265 tpm_state.log_area_minimum_length);
266
267 tpm_state.log_area_next_entry = tpm_state.log_area_start_address;
268 tpm_state.log_area_last_entry = NULL;
269 tpm_state.entry_count = 0;
270}
271
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500272/*
273 * Extend the ACPI log with the given entry by copying the
274 * entry data into the log.
275 * Input
276 * pcpes : Pointer to the event 'header' to be copied into the log
277 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500278 *
279 * Output:
280 * Returns an error code in case of faiure, 0 in case of success
281 */
282static u32
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500283tpm_extend_acpi_log(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500284{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500285 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
286 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
287
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500288 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500289 return TCG_PC_LOGOVERFLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500290
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500291 u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500292
293 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
294 tpm_state.log_area_minimum_length) {
295 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500296 return TCG_PC_LOGOVERFLOW;
297 }
298
Kevin O'Connorbad6f962015-11-23 22:32:09 -0500299 memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
300 memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes),
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500301 event, pcpes->eventdatasize);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500302
303 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
304 tpm_state.log_area_next_entry += size;
305 tpm_state.entry_count++;
306
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500307 return 0;
308}
309
310
311/****************************************************************
312 * Helper functions
313 ****************************************************************/
314
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400315/*
316 * Send a TPM command with the given ordinal. Append the given buffer
317 * containing all data in network byte order to the command (this is
318 * the custom part per command) and expect a response of the given size.
319 * If a buffer is provided, the response will be copied into it.
320 */
321static u32
Stefan Berger47b9df52015-11-21 14:54:40 -0500322build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
323 u8 *resbuffer, u32 return_size, u32 *returnCode,
324 enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400325{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500326 struct {
327 struct tpm_req_header trqh;
328 u8 cmd[20];
329 } PACKED req = {
330 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500331 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500332 .trqh.ordinal = cpu_to_be32(ordinal),
333 };
Stefan Bergerece25612015-11-12 10:14:46 -0500334 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400335 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400336 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400337 memset(obuffer, 0x0, sizeof(obuffer));
338
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500339 if (return_size > sizeof(obuffer) || append_size > sizeof(req.cmd)) {
340 warn_internalerror();
341 return TCG_FIRMWARE_ERROR;
342 }
343 if (append_size)
344 memcpy(req.cmd, append, append_size);
345
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500346 u32 rc = transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400347 if (rc)
348 return rc;
349
350 *returnCode = be32_to_cpu(trsh->errcode);
351
352 if (resbuffer)
353 memcpy(resbuffer, trsh, return_size);
354
355 return 0;
356}
357
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500358static void
359tpm_set_failure(void)
360{
361 u32 returnCode;
362
363 /* we will try to deactivate the TPM now - ignoring all errors */
364 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
365 PhysicalPresence_CMD_ENABLE,
366 sizeof(PhysicalPresence_CMD_ENABLE),
367 NULL, 0, &returnCode,
368 TPM_DURATION_TYPE_SHORT);
369
370 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
371 PhysicalPresence_PRESENT,
372 sizeof(PhysicalPresence_PRESENT),
373 NULL, 0, &returnCode,
374 TPM_DURATION_TYPE_SHORT);
375
376 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
377 NULL, 0, NULL, 0, &returnCode,
378 TPM_DURATION_TYPE_SHORT);
379
380 tpm_state.tpm_working = 0;
381}
382
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400383static u32
384determine_timeouts(void)
385{
386 u32 rc;
387 u32 returnCode;
388 struct tpm_res_getcap_timeouts timeouts;
389 struct tpm_res_getcap_durations durations;
390 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
391 u32 i;
392
Stefan Berger5aa2a752015-03-23 14:22:17 -0400393 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400394 GetCapability_Timeouts,
395 sizeof(GetCapability_Timeouts),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400396 (u8 *)&timeouts, sizeof(timeouts),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400397 &returnCode, TPM_DURATION_TYPE_SHORT);
398
399 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
400 " = 0x%08x\n", returnCode);
401
402 if (rc || returnCode)
403 goto err_exit;
404
Stefan Berger5aa2a752015-03-23 14:22:17 -0400405 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400406 GetCapability_Durations,
407 sizeof(GetCapability_Durations),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400408 (u8 *)&durations, sizeof(durations),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400409 &returnCode, TPM_DURATION_TYPE_SHORT);
410
411 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
412 " = 0x%08x\n", returnCode);
413
414 if (rc || returnCode)
415 goto err_exit;
416
417 for (i = 0; i < 3; i++)
418 durations.durations[i] = be32_to_cpu(durations.durations[i]);
419
420 for (i = 0; i < 4; i++)
421 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
422
423 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
424 timeouts.timeouts[0],
425 timeouts.timeouts[1],
426 timeouts.timeouts[2],
427 timeouts.timeouts[3]);
428
429 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
430 durations.durations[0],
431 durations.durations[1],
432 durations.durations[2]);
433
434
435 td->set_timeouts(timeouts.timeouts, durations.durations);
436
437 return 0;
438
439err_exit:
440 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
441
Stefan Berger7fce1d92015-11-12 10:14:45 -0500442 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400443 if (rc)
444 return rc;
445 return TCG_TCG_COMMAND_ERROR;
446}
447
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500448static u32
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500449tpm_extend(u8 *hash, u32 pcrindex)
450{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500451 struct tpm_req_extend tre = {
452 .tag = cpu_to_be16(TPM_TAG_RQU_CMD),
453 .totlen = cpu_to_be32(sizeof(tre)),
454 .ordinal = cpu_to_be32(TPM_ORD_Extend),
455 .pcrindex = cpu_to_be32(pcrindex),
456 };
457 struct tpm_rsp_extend rsp;
458 u32 resp_length = sizeof(rsp);
459
460 memcpy(tre.digest, hash, sizeof(tre.digest));
461
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500462 u32 rc = transmit(0, (void*)&tre, &rsp, &resp_length,
463 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500464 if (rc || resp_length != sizeof(rsp))
465 tpm_set_failure();
466
467 return rc;
468}
469
470static u32
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500471tpm_log_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500472{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500473 if (pcpes->pcrindex >= 24)
474 return TCG_INVALID_INPUT_PARA;
475
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500476 if (!has_working_tpm())
477 return TCG_GENERAL_ERROR;
478
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500479 u32 rc = tpm_extend_acpi_log(pcpes, event);
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500480 if (rc)
481 tpm_set_failure();
482 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500483}
484
485static u32
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500486tpm_log_extend_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500487{
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500488 u32 rc = tpm_log_event(pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500489 if (rc)
490 return rc;
Kevin O'Connor8149f1b2015-11-22 16:43:47 -0500491 return tpm_extend(pcpes->digest, pcpes->pcrindex);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500492}
493
Kevin O'Connor92244402015-11-22 16:54:18 -0500494static void
495tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
496{
497 if (hashdata)
498 sha1(hashdata, hashdata_length, pcpes->digest);
499}
500
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500501/*
502 * Add a measurement to the log; the data at data_seg:data/length are
503 * appended to the TCG_PCClientPCREventStruct
504 *
505 * Input parameters:
506 * pcrindex : which PCR to extend
507 * event_type : type of event; specs section on 'Event Types'
508 * event : pointer to info (e.g., string) to be added to log as-is
509 * event_length: length of the event
510 * hashdata : pointer to the data to be hashed
511 * hashdata_length: length of the data to be hashed
512 */
513static u32
514tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
515 const char *event, u32 event_length,
516 const u8 *hashdata, u32 hashdata_length)
517{
518 struct pcpes pcpes = {
519 .pcrindex = pcrindex,
520 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500521 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500522 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500523 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500524 return tpm_log_extend_event(&pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500525}
526
527
528/****************************************************************
529 * Setup and Measurements
530 ****************************************************************/
531
Kevin O'Connora6175422015-11-22 11:28:14 -0500532// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500533static u32
Kevin O'Connora6175422015-11-22 11:28:14 -0500534tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500535{
Kevin O'Connora6175422015-11-22 11:28:14 -0500536 u32 len = strlen(string);
537 return tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
538 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500539}
540
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500541/*
542 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
543 */
544static u32
545tpm_add_event_separators(void)
546{
547 u32 rc;
548 u32 pcrIndex = 0;
549
550 if (!CONFIG_TCGBIOS)
551 return 0;
552
553 if (!has_working_tpm())
554 return TCG_GENERAL_ERROR;
555
Kevin O'Connora6175422015-11-22 11:28:14 -0500556 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500557 while (pcrIndex <= 7) {
Kevin O'Connora6175422015-11-22 11:28:14 -0500558 rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
559 NULL, 0,
560 (u8 *)evt_separator,
561 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500562 if (rc)
563 break;
564 pcrIndex ++;
565 }
566
567 return rc;
568}
569
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500570static u32
571tpm_smbios_measure(void)
572{
573 if (!CONFIG_TCGBIOS)
574 return 0;
575
576 if (!has_working_tpm())
577 return TCG_GENERAL_ERROR;
578
579 u32 rc;
580 struct pcctes pcctes = {
581 .eventid = 1,
582 .eventdatasize = SHA1_BUFSIZE,
583 };
584 struct smbios_entry_point *sep = SMBiosAddr;
585
586 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
587
588 if (!sep)
589 return 0;
590
591 rc = sha1((const u8 *)sep->structure_table_address,
592 sep->structure_table_length, pcctes.digest);
593 if (rc)
594 return rc;
595
596 return tpm_add_measurement_to_log(1,
597 EV_EVENT_TAG,
598 (const char *)&pcctes, sizeof(pcctes),
599 (u8 *)&pcctes, sizeof(pcctes));
600}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400601
602static u32
603tpm_startup(void)
604{
605 u32 rc;
606 u32 returnCode;
607
608 if (!has_working_tpm())
609 return TCG_GENERAL_ERROR;
610
611 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400612 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400613 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400614 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400615
616 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
617 returnCode);
618
619 if (CONFIG_COREBOOT) {
620 /* with other firmware on the system the TPM may already have been
621 * initialized
622 */
623 if (returnCode == TPM_INVALID_POSTINIT)
624 returnCode = 0;
625 }
626
627 if (rc || returnCode)
628 goto err_exit;
629
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500630 rc = determine_timeouts();
631 if (rc)
632 goto err_exit;
633
Stefan Berger5aa2a752015-03-23 14:22:17 -0400634 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400635 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400636
637 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
638 returnCode);
639
640 if (rc || returnCode)
641 goto err_exit;
642
Stefan Berger5aa2a752015-03-23 14:22:17 -0400643 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400644 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400645
646 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
647 returnCode);
648
649 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
650 goto err_exit;
651
Stefan Berger2aff1c12015-05-26 15:48:33 -0400652 rc = tpm_smbios_measure();
653 if (rc)
654 goto err_exit;
655
Kevin O'Connor12575332015-11-22 11:34:38 -0500656 rc = tpm_add_action(2, "Start Option ROM Scan");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400657 if (rc)
658 goto err_exit;
659
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400660 return 0;
661
662err_exit:
663 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
664
Stefan Berger7fce1d92015-11-12 10:14:45 -0500665 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400666 if (rc)
667 return rc;
668 return TCG_TCG_COMMAND_ERROR;
669}
670
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500671/*
672 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
673 where the TCPA table is.
674 */
675static void
676tpm_acpi_init(void)
677{
678 tpm_state.if_shutdown = 0;
679 tpm_state.tpm_probed = 0;
680 tpm_state.tpm_found = 0;
681 tpm_state.tpm_working = 0;
682
683 if (!has_working_tpm()) {
684 tpm_state.if_shutdown = 1;
685 return;
686 }
687
688 reset_acpi_log();
689}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400690
Kevin O'Connord6aca442015-06-10 11:00:17 -0400691void
692tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400693{
694 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400695 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400696
697 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400698 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400699 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400700
Kevin O'Connord6aca442015-06-10 11:00:17 -0400701 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400702}
703
Kevin O'Connord6aca442015-06-10 11:00:17 -0400704void
705tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400706{
707 u32 rc;
708 u32 returnCode;
709
710 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400711 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400712
713 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400714 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400715
Stefan Berger5aa2a752015-03-23 14:22:17 -0400716 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400717 PhysicalPresence_CMD_ENABLE,
718 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400719 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400720 if (rc || returnCode)
721 goto err_exit;
722
Stefan Berger5aa2a752015-03-23 14:22:17 -0400723 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400724 PhysicalPresence_NOT_PRESENT_LOCK,
725 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400726 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400727 if (rc || returnCode)
728 goto err_exit;
729
Kevin O'Connor12575332015-11-22 11:34:38 -0500730 rc = tpm_add_action(4, "Calling INT 19h");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400731 if (rc)
732 goto err_exit;
733
734 rc = tpm_add_event_separators();
735 if (rc)
736 goto err_exit;
737
Kevin O'Connord6aca442015-06-10 11:00:17 -0400738 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400739
740err_exit:
741 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
742
Stefan Berger7fce1d92015-11-12 10:14:45 -0500743 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400744}
745
Stefan Berger5aa2a752015-03-23 14:22:17 -0400746/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500747 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400748 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500749u32
750tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400751{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500752 if (!CONFIG_TCGBIOS)
753 return 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400754
Stefan Berger7fce1d92015-11-12 10:14:45 -0500755 if (!has_working_tpm())
756 return TCG_GENERAL_ERROR;
757
Stefan Berger5aa2a752015-03-23 14:22:17 -0400758 u32 rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500759 struct pcctes_romex pcctes = {
760 .eventid = 7,
761 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400762 };
763
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500764 rc = sha1((const u8 *)addr, len, pcctes.digest);
Stefan Berger6c376b42015-11-12 10:14:49 -0500765 if (rc)
766 return rc;
767
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500768 return tpm_add_measurement_to_log(2,
769 EV_EVENT_TAG,
770 (const char *)&pcctes, sizeof(pcctes),
771 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500772}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400773
Stefan Berger2aff1c12015-05-26 15:48:33 -0400774u32
775tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
776{
777 if (!CONFIG_TCGBIOS)
778 return 0;
779
780 if (!has_working_tpm())
781 return TCG_GENERAL_ERROR;
782
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500783 const char *string = "Booting BCV device 00h (Floppy)";
784 if (bootdrv == 0x80)
785 string = "Booting BCV device 80h (HDD)";
786 u32 rc = tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400787 if (rc)
788 return rc;
789
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500790 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
791 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500792 string = "MBR";
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500793 rc = tpm_add_measurement_to_log(4, EV_IPL,
794 string, strlen(string),
795 addr, 0x1b8);
796 if (rc)
797 return rc;
798
799 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
800 string = "MBR PARTITION_TABLE";
801 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
802 string, strlen(string),
803 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400804}
805
806u32
807tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
808{
809 if (!CONFIG_TCGBIOS)
810 return 0;
811
812 if (!has_working_tpm())
813 return TCG_GENERAL_ERROR;
814
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500815 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400816 if (rc)
817 return rc;
818
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500819 /* specs: see section 'El Torito' */
820 const char *string = "EL TORITO IPL";
821 return tpm_add_measurement_to_log(4, EV_IPL,
822 string, strlen(string),
823 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400824}
825
826u32
827tpm_add_cdrom_catalog(const u8 *addr, u32 length)
828{
829 if (!CONFIG_TCGBIOS)
830 return 0;
831
832 if (!has_working_tpm())
833 return TCG_GENERAL_ERROR;
834
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500835 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400836 if (rc)
837 return rc;
838
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500839 /* specs: see section 'El Torito' */
840 const char *string = "BOOT CATALOG";
841 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
842 string, strlen(string),
843 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400844}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400845
Kevin O'Connord6aca442015-06-10 11:00:17 -0400846void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400847tpm_s3_resume(void)
848{
849 u32 rc;
850 u32 returnCode;
851
852 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400853 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400854
855 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400856 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400857
858 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
859
Stefan Berger5aa2a752015-03-23 14:22:17 -0400860 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400861 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400862 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400863
864 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
865 returnCode);
866
867 if (rc || returnCode)
868 goto err_exit;
869
Kevin O'Connord6aca442015-06-10 11:00:17 -0400870 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400871
872err_exit:
873 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
874
Stefan Berger7fce1d92015-11-12 10:14:45 -0500875 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400876}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500877
878
879/****************************************************************
880 * BIOS interface
881 ****************************************************************/
882
883static inline void *input_buf32(struct bregs *regs)
884{
885 return MAKE_FLATPTR(regs->es, regs->di);
886}
887
888static inline void *output_buf32(struct bregs *regs)
889{
890 return MAKE_FLATPTR(regs->ds, regs->si);
891}
892
893static u32
894hash_log_extend_event_int(const struct hleei_short *hleei_s,
895 struct hleeo *hleeo)
896{
897 u32 rc = 0;
898 struct hleo hleo;
899 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
900 const void *logdataptr;
901 u32 logdatalen;
902 struct pcpes *pcpes;
903 u32 pcrindex;
904
905 if (is_preboot_if_shutdown() != 0) {
906 rc = TCG_INTERFACE_SHUTDOWN;
907 goto err_exit;
908 }
909
910 /* short or long version? */
911 switch (hleei_s->ipblength) {
912 case sizeof(struct hleei_short):
913 /* short */
914 logdataptr = hleei_s->logdataptr;
915 logdatalen = hleei_s->logdatalen;
916 pcrindex = hleei_s->pcrindex;
917 break;
918
919 case sizeof(struct hleei_long):
920 /* long */
921 logdataptr = hleei_l->logdataptr;
922 logdatalen = hleei_l->logdatalen;
923 pcrindex = hleei_l->pcrindex;
924 break;
925
926 default:
927 /* bad input block */
928 rc = TCG_INVALID_INPUT_PARA;
929 goto err_exit;
930 }
931
932 pcpes = (struct pcpes *)logdataptr;
933
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500934 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
935 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500936 rc = TCG_INVALID_INPUT_PARA;
937 goto err_exit;
938 }
939
Kevin O'Connor92244402015-11-22 16:54:18 -0500940 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500941 rc = tpm_log_extend_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500942 if (rc)
943 goto err_exit;
944
945 hleeo->opblength = sizeof(struct hleeo);
946 hleeo->reserved = 0;
947 hleeo->eventnumber = hleo.eventnumber;
948
949err_exit:
950 if (rc != 0) {
951 hleeo->opblength = 4;
952 hleeo->reserved = 0;
953 }
954
955 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500956}
957
958static u32
959pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
960{
961 u32 rc = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500962
963 if (is_preboot_if_shutdown()) {
964 rc = TCG_INTERFACE_SHUTDOWN;
965 goto err_exit;
966 }
967
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500968 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500969
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500970 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
971 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
972 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500973 rc = TCG_INVALID_INPUT_PARA;
974 goto err_exit;
975 }
976
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500977 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
978 rc = transmit(0, trh, pttto->tpmopout, &resbuflen,
979 TPM_DURATION_TYPE_LONG /* worst case */);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500980 if (rc)
981 goto err_exit;
982
983 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
984 pttto->reserved = 0;
985
986err_exit:
987 if (rc != 0) {
988 pttto->opblength = 4;
989 pttto->reserved = 0;
990 }
991
992 return rc;
993}
994
995static u32
996shutdown_preboot_interface(void)
997{
998 u32 rc = 0;
999
1000 if (!is_preboot_if_shutdown()) {
1001 tpm_state.if_shutdown = 1;
1002 } else {
1003 rc = TCG_INTERFACE_SHUTDOWN;
1004 }
1005
1006 return rc;
1007}
1008
1009static u32
1010hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1011{
1012 u32 rc = 0;
1013 u16 size;
1014 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001015
1016 if (is_preboot_if_shutdown() != 0) {
1017 rc = TCG_INTERFACE_SHUTDOWN;
1018 goto err_exit;
1019 }
1020
1021 size = hlei->ipblength;
1022 if (size != sizeof(*hlei)) {
1023 rc = TCG_INVALID_INPUT_PARA;
1024 goto err_exit;
1025 }
1026
1027 pcpes = (struct pcpes *)hlei->logdataptr;
1028
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001029 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
1030 || pcpes->eventtype != hlei->logeventtype
1031 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001032 rc = TCG_INVALID_INPUT_PARA;
1033 goto err_exit;
1034 }
1035
Kevin O'Connor92244402015-11-22 16:54:18 -05001036 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001037 rc = tpm_log_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001038 if (rc)
1039 goto err_exit;
1040
1041 /* updating the log was fine */
1042 hleo->opblength = sizeof(struct hleo);
1043 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001044 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001045
1046err_exit:
1047 if (rc != 0) {
1048 hleo->opblength = 2;
1049 hleo->reserved = 0;
1050 }
1051
1052 return rc;
1053}
1054
1055static u32
1056hash_all_int(const struct hai *hai, u8 *hash)
1057{
1058 if (is_preboot_if_shutdown() != 0)
1059 return TCG_INTERFACE_SHUTDOWN;
1060
1061 if (hai->ipblength != sizeof(struct hai) ||
1062 hai->hashdataptr == 0 ||
1063 hai->hashdatalen == 0 ||
1064 hai->algorithmid != TPM_ALG_SHA)
1065 return TCG_INVALID_INPUT_PARA;
1066
1067 return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1068}
1069
1070static u32
1071tss_int(struct ti *ti, struct to *to)
1072{
1073 u32 rc = 0;
1074
1075 if (is_preboot_if_shutdown() == 0) {
1076 rc = TCG_PC_UNSUPPORTED;
1077 } else {
1078 rc = TCG_INTERFACE_SHUTDOWN;
1079 }
1080
1081 to->opblength = sizeof(struct to);
1082 to->reserved = 0;
1083
1084 return rc;
1085}
1086
1087static u32
1088compact_hash_log_extend_event_int(u8 *buffer,
1089 u32 info,
1090 u32 length,
1091 u32 pcrindex,
1092 u32 *edx_ptr)
1093{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001094 struct pcpes pcpes = {
1095 .pcrindex = pcrindex,
1096 .eventtype = EV_COMPACT_HASH,
1097 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001098 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001099
1100 if (is_preboot_if_shutdown() != 0)
1101 return TCG_INTERFACE_SHUTDOWN;
1102
Kevin O'Connor92244402015-11-22 16:54:18 -05001103 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001104 u32 rc = tpm_log_extend_event(&pcpes, &info);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001105 if (rc == 0)
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001106 *edx_ptr = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001107
1108 return rc;
1109}
1110
1111void VISIBLE32FLAT
1112tpm_interrupt_handler32(struct bregs *regs)
1113{
1114 if (!CONFIG_TCGBIOS)
1115 return;
1116
1117 set_cf(regs, 0);
1118
1119 if (!has_working_tpm()) {
1120 regs->eax = TCG_GENERAL_ERROR;
1121 return;
1122 }
1123
1124 switch ((enum irq_ids)regs->al) {
1125 case TCG_StatusCheck:
1126 if (is_tpm_present() == 0) {
1127 /* no TPM available */
1128 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1129 } else {
1130 regs->eax = 0;
1131 regs->ebx = TCG_MAGIC;
1132 regs->ch = TCG_VERSION_MAJOR;
1133 regs->cl = TCG_VERSION_MINOR;
1134 regs->edx = 0x0;
1135 regs->esi = (u32)tpm_state.log_area_start_address;
1136 regs->edi = (u32)tpm_state.log_area_last_entry;
1137 }
1138 break;
1139
1140 case TCG_HashLogExtendEvent:
1141 regs->eax =
1142 hash_log_extend_event_int(
1143 (struct hleei_short *)input_buf32(regs),
1144 (struct hleeo *)output_buf32(regs));
1145 break;
1146
1147 case TCG_PassThroughToTPM:
1148 regs->eax =
1149 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1150 (struct pttto *)output_buf32(regs));
1151 break;
1152
1153 case TCG_ShutdownPreBootInterface:
1154 regs->eax = shutdown_preboot_interface();
1155 break;
1156
1157 case TCG_HashLogEvent:
1158 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1159 (struct hleo*)output_buf32(regs));
1160 break;
1161
1162 case TCG_HashAll:
1163 regs->eax =
1164 hash_all_int((struct hai*)input_buf32(regs),
1165 (u8 *)output_buf32(regs));
1166 break;
1167
1168 case TCG_TSS:
1169 regs->eax = tss_int((struct ti*)input_buf32(regs),
1170 (struct to*)output_buf32(regs));
1171 break;
1172
1173 case TCG_CompactHashLogExtendEvent:
1174 regs->eax =
1175 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1176 regs->esi,
1177 regs->ecx,
1178 regs->edx,
1179 &regs->edx);
1180 break;
1181
1182 default:
1183 set_cf(regs, 1);
1184 }
1185
1186 return;
1187}