blob: 704993f78fa9202e7e2431d811c2748c61255b80 [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'Connor4e7cf9c2015-11-22 18:51:31 -0500283tpm_log_event(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'Connor4e7cf9c2015-11-22 18:51:31 -0500471tpm_log_extend_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500472{
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500473 if (!has_working_tpm())
474 return TCG_GENERAL_ERROR;
475
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500476 if (pcpes->pcrindex >= 24)
477 return TCG_INVALID_INPUT_PARA;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500478
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500479 u32 rc = tpm_log_event(pcpes, event);
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500480 if (rc) {
481 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500482 return rc;
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500483 }
Kevin O'Connor8149f1b2015-11-22 16:43:47 -0500484 return tpm_extend(pcpes->digest, pcpes->pcrindex);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500485}
486
Kevin O'Connor92244402015-11-22 16:54:18 -0500487static void
488tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
489{
490 if (hashdata)
491 sha1(hashdata, hashdata_length, pcpes->digest);
492}
493
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500494/*
495 * Add a measurement to the log; the data at data_seg:data/length are
496 * appended to the TCG_PCClientPCREventStruct
497 *
498 * Input parameters:
499 * pcrindex : which PCR to extend
500 * event_type : type of event; specs section on 'Event Types'
501 * event : pointer to info (e.g., string) to be added to log as-is
502 * event_length: length of the event
503 * hashdata : pointer to the data to be hashed
504 * hashdata_length: length of the data to be hashed
505 */
506static u32
507tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
508 const char *event, u32 event_length,
509 const u8 *hashdata, u32 hashdata_length)
510{
511 struct pcpes pcpes = {
512 .pcrindex = pcrindex,
513 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500514 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500515 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500516 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500517 return tpm_log_extend_event(&pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500518}
519
520
521/****************************************************************
522 * Setup and Measurements
523 ****************************************************************/
524
Kevin O'Connora6175422015-11-22 11:28:14 -0500525// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500526static u32
Kevin O'Connora6175422015-11-22 11:28:14 -0500527tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500528{
Kevin O'Connora6175422015-11-22 11:28:14 -0500529 u32 len = strlen(string);
530 return tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
531 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500532}
533
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500534/*
535 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
536 */
537static u32
538tpm_add_event_separators(void)
539{
540 u32 rc;
541 u32 pcrIndex = 0;
542
543 if (!CONFIG_TCGBIOS)
544 return 0;
545
546 if (!has_working_tpm())
547 return TCG_GENERAL_ERROR;
548
Kevin O'Connora6175422015-11-22 11:28:14 -0500549 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500550 while (pcrIndex <= 7) {
Kevin O'Connora6175422015-11-22 11:28:14 -0500551 rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
552 NULL, 0,
553 (u8 *)evt_separator,
554 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500555 if (rc)
556 break;
557 pcrIndex ++;
558 }
559
560 return rc;
561}
562
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500563static u32
564tpm_smbios_measure(void)
565{
566 if (!CONFIG_TCGBIOS)
567 return 0;
568
569 if (!has_working_tpm())
570 return TCG_GENERAL_ERROR;
571
572 u32 rc;
573 struct pcctes pcctes = {
574 .eventid = 1,
575 .eventdatasize = SHA1_BUFSIZE,
576 };
577 struct smbios_entry_point *sep = SMBiosAddr;
578
579 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
580
581 if (!sep)
582 return 0;
583
584 rc = sha1((const u8 *)sep->structure_table_address,
585 sep->structure_table_length, pcctes.digest);
586 if (rc)
587 return rc;
588
589 return tpm_add_measurement_to_log(1,
590 EV_EVENT_TAG,
591 (const char *)&pcctes, sizeof(pcctes),
592 (u8 *)&pcctes, sizeof(pcctes));
593}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400594
595static u32
596tpm_startup(void)
597{
598 u32 rc;
599 u32 returnCode;
600
601 if (!has_working_tpm())
602 return TCG_GENERAL_ERROR;
603
604 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400605 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400606 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400607 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400608
609 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
610 returnCode);
611
612 if (CONFIG_COREBOOT) {
613 /* with other firmware on the system the TPM may already have been
614 * initialized
615 */
616 if (returnCode == TPM_INVALID_POSTINIT)
617 returnCode = 0;
618 }
619
620 if (rc || returnCode)
621 goto err_exit;
622
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500623 rc = determine_timeouts();
624 if (rc)
625 goto err_exit;
626
Stefan Berger5aa2a752015-03-23 14:22:17 -0400627 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400628 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400629
630 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
631 returnCode);
632
633 if (rc || returnCode)
634 goto err_exit;
635
Stefan Berger5aa2a752015-03-23 14:22:17 -0400636 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400637 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400638
639 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
640 returnCode);
641
642 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
643 goto err_exit;
644
Stefan Berger2aff1c12015-05-26 15:48:33 -0400645 rc = tpm_smbios_measure();
646 if (rc)
647 goto err_exit;
648
Kevin O'Connor12575332015-11-22 11:34:38 -0500649 rc = tpm_add_action(2, "Start Option ROM Scan");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400650 if (rc)
651 goto err_exit;
652
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400653 return 0;
654
655err_exit:
656 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
657
Stefan Berger7fce1d92015-11-12 10:14:45 -0500658 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400659 if (rc)
660 return rc;
661 return TCG_TCG_COMMAND_ERROR;
662}
663
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500664/*
665 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
666 where the TCPA table is.
667 */
668static void
669tpm_acpi_init(void)
670{
671 tpm_state.if_shutdown = 0;
672 tpm_state.tpm_probed = 0;
673 tpm_state.tpm_found = 0;
674 tpm_state.tpm_working = 0;
675
676 if (!has_working_tpm()) {
677 tpm_state.if_shutdown = 1;
678 return;
679 }
680
681 reset_acpi_log();
682}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400683
Kevin O'Connord6aca442015-06-10 11:00:17 -0400684void
685tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400686{
687 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400688 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400689
690 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400691 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400692 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400693
Kevin O'Connord6aca442015-06-10 11:00:17 -0400694 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400695}
696
Kevin O'Connord6aca442015-06-10 11:00:17 -0400697void
698tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400699{
700 u32 rc;
701 u32 returnCode;
702
703 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400704 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400705
706 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400707 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400708
Stefan Berger5aa2a752015-03-23 14:22:17 -0400709 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400710 PhysicalPresence_CMD_ENABLE,
711 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400712 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400713 if (rc || returnCode)
714 goto err_exit;
715
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_NOT_PRESENT_LOCK,
718 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
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
Kevin O'Connor12575332015-11-22 11:34:38 -0500723 rc = tpm_add_action(4, "Calling INT 19h");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400724 if (rc)
725 goto err_exit;
726
727 rc = tpm_add_event_separators();
728 if (rc)
729 goto err_exit;
730
Kevin O'Connord6aca442015-06-10 11:00:17 -0400731 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400732
733err_exit:
734 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
735
Stefan Berger7fce1d92015-11-12 10:14:45 -0500736 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400737}
738
Stefan Berger5aa2a752015-03-23 14:22:17 -0400739/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500740 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400741 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500742u32
743tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400744{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500745 if (!CONFIG_TCGBIOS)
746 return 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400747
Stefan Berger7fce1d92015-11-12 10:14:45 -0500748 if (!has_working_tpm())
749 return TCG_GENERAL_ERROR;
750
Stefan Berger5aa2a752015-03-23 14:22:17 -0400751 u32 rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500752 struct pcctes_romex pcctes = {
753 .eventid = 7,
754 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400755 };
756
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500757 rc = sha1((const u8 *)addr, len, pcctes.digest);
Stefan Berger6c376b42015-11-12 10:14:49 -0500758 if (rc)
759 return rc;
760
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500761 return tpm_add_measurement_to_log(2,
762 EV_EVENT_TAG,
763 (const char *)&pcctes, sizeof(pcctes),
764 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500765}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400766
Stefan Berger2aff1c12015-05-26 15:48:33 -0400767u32
768tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
769{
770 if (!CONFIG_TCGBIOS)
771 return 0;
772
773 if (!has_working_tpm())
774 return TCG_GENERAL_ERROR;
775
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500776 const char *string = "Booting BCV device 00h (Floppy)";
777 if (bootdrv == 0x80)
778 string = "Booting BCV device 80h (HDD)";
779 u32 rc = tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400780 if (rc)
781 return rc;
782
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500783 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
784 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500785 string = "MBR";
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500786 rc = tpm_add_measurement_to_log(4, EV_IPL,
787 string, strlen(string),
788 addr, 0x1b8);
789 if (rc)
790 return rc;
791
792 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
793 string = "MBR PARTITION_TABLE";
794 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
795 string, strlen(string),
796 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400797}
798
799u32
800tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
801{
802 if (!CONFIG_TCGBIOS)
803 return 0;
804
805 if (!has_working_tpm())
806 return TCG_GENERAL_ERROR;
807
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500808 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400809 if (rc)
810 return rc;
811
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500812 /* specs: see section 'El Torito' */
813 const char *string = "EL TORITO IPL";
814 return tpm_add_measurement_to_log(4, EV_IPL,
815 string, strlen(string),
816 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400817}
818
819u32
820tpm_add_cdrom_catalog(const u8 *addr, u32 length)
821{
822 if (!CONFIG_TCGBIOS)
823 return 0;
824
825 if (!has_working_tpm())
826 return TCG_GENERAL_ERROR;
827
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500828 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400829 if (rc)
830 return rc;
831
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500832 /* specs: see section 'El Torito' */
833 const char *string = "BOOT CATALOG";
834 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
835 string, strlen(string),
836 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400837}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400838
Kevin O'Connord6aca442015-06-10 11:00:17 -0400839void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400840tpm_s3_resume(void)
841{
842 u32 rc;
843 u32 returnCode;
844
845 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400846 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400847
848 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400849 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400850
851 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
852
Stefan Berger5aa2a752015-03-23 14:22:17 -0400853 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400854 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400855 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400856
857 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
858 returnCode);
859
860 if (rc || returnCode)
861 goto err_exit;
862
Kevin O'Connord6aca442015-06-10 11:00:17 -0400863 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400864
865err_exit:
866 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
867
Stefan Berger7fce1d92015-11-12 10:14:45 -0500868 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400869}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500870
871
872/****************************************************************
873 * BIOS interface
874 ****************************************************************/
875
876static inline void *input_buf32(struct bregs *regs)
877{
878 return MAKE_FLATPTR(regs->es, regs->di);
879}
880
881static inline void *output_buf32(struct bregs *regs)
882{
883 return MAKE_FLATPTR(regs->ds, regs->si);
884}
885
886static u32
887hash_log_extend_event_int(const struct hleei_short *hleei_s,
888 struct hleeo *hleeo)
889{
890 u32 rc = 0;
891 struct hleo hleo;
892 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
893 const void *logdataptr;
894 u32 logdatalen;
895 struct pcpes *pcpes;
896 u32 pcrindex;
897
898 if (is_preboot_if_shutdown() != 0) {
899 rc = TCG_INTERFACE_SHUTDOWN;
900 goto err_exit;
901 }
902
903 /* short or long version? */
904 switch (hleei_s->ipblength) {
905 case sizeof(struct hleei_short):
906 /* short */
907 logdataptr = hleei_s->logdataptr;
908 logdatalen = hleei_s->logdatalen;
909 pcrindex = hleei_s->pcrindex;
910 break;
911
912 case sizeof(struct hleei_long):
913 /* long */
914 logdataptr = hleei_l->logdataptr;
915 logdatalen = hleei_l->logdatalen;
916 pcrindex = hleei_l->pcrindex;
917 break;
918
919 default:
920 /* bad input block */
921 rc = TCG_INVALID_INPUT_PARA;
922 goto err_exit;
923 }
924
925 pcpes = (struct pcpes *)logdataptr;
926
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500927 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
928 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500929 rc = TCG_INVALID_INPUT_PARA;
930 goto err_exit;
931 }
932
Kevin O'Connor92244402015-11-22 16:54:18 -0500933 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500934 rc = tpm_log_extend_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500935 if (rc)
936 goto err_exit;
937
938 hleeo->opblength = sizeof(struct hleeo);
939 hleeo->reserved = 0;
940 hleeo->eventnumber = hleo.eventnumber;
941
942err_exit:
943 if (rc != 0) {
944 hleeo->opblength = 4;
945 hleeo->reserved = 0;
946 }
947
948 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500949}
950
951static u32
952pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
953{
954 u32 rc = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500955
956 if (is_preboot_if_shutdown()) {
957 rc = TCG_INTERFACE_SHUTDOWN;
958 goto err_exit;
959 }
960
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500961 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500962
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500963 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
964 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
965 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500966 rc = TCG_INVALID_INPUT_PARA;
967 goto err_exit;
968 }
969
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500970 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
971 rc = transmit(0, trh, pttto->tpmopout, &resbuflen,
972 TPM_DURATION_TYPE_LONG /* worst case */);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500973 if (rc)
974 goto err_exit;
975
976 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
977 pttto->reserved = 0;
978
979err_exit:
980 if (rc != 0) {
981 pttto->opblength = 4;
982 pttto->reserved = 0;
983 }
984
985 return rc;
986}
987
988static u32
989shutdown_preboot_interface(void)
990{
991 u32 rc = 0;
992
993 if (!is_preboot_if_shutdown()) {
994 tpm_state.if_shutdown = 1;
995 } else {
996 rc = TCG_INTERFACE_SHUTDOWN;
997 }
998
999 return rc;
1000}
1001
1002static u32
1003hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1004{
1005 u32 rc = 0;
1006 u16 size;
1007 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001008
1009 if (is_preboot_if_shutdown() != 0) {
1010 rc = TCG_INTERFACE_SHUTDOWN;
1011 goto err_exit;
1012 }
1013
1014 size = hlei->ipblength;
1015 if (size != sizeof(*hlei)) {
1016 rc = TCG_INVALID_INPUT_PARA;
1017 goto err_exit;
1018 }
1019
1020 pcpes = (struct pcpes *)hlei->logdataptr;
1021
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001022 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
1023 || pcpes->eventtype != hlei->logeventtype
1024 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001025 rc = TCG_INVALID_INPUT_PARA;
1026 goto err_exit;
1027 }
1028
Kevin O'Connor92244402015-11-22 16:54:18 -05001029 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001030 rc = tpm_log_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001031 if (rc)
1032 goto err_exit;
1033
1034 /* updating the log was fine */
1035 hleo->opblength = sizeof(struct hleo);
1036 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001037 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001038
1039err_exit:
1040 if (rc != 0) {
1041 hleo->opblength = 2;
1042 hleo->reserved = 0;
1043 }
1044
1045 return rc;
1046}
1047
1048static u32
1049hash_all_int(const struct hai *hai, u8 *hash)
1050{
1051 if (is_preboot_if_shutdown() != 0)
1052 return TCG_INTERFACE_SHUTDOWN;
1053
1054 if (hai->ipblength != sizeof(struct hai) ||
1055 hai->hashdataptr == 0 ||
1056 hai->hashdatalen == 0 ||
1057 hai->algorithmid != TPM_ALG_SHA)
1058 return TCG_INVALID_INPUT_PARA;
1059
1060 return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1061}
1062
1063static u32
1064tss_int(struct ti *ti, struct to *to)
1065{
1066 u32 rc = 0;
1067
1068 if (is_preboot_if_shutdown() == 0) {
1069 rc = TCG_PC_UNSUPPORTED;
1070 } else {
1071 rc = TCG_INTERFACE_SHUTDOWN;
1072 }
1073
1074 to->opblength = sizeof(struct to);
1075 to->reserved = 0;
1076
1077 return rc;
1078}
1079
1080static u32
1081compact_hash_log_extend_event_int(u8 *buffer,
1082 u32 info,
1083 u32 length,
1084 u32 pcrindex,
1085 u32 *edx_ptr)
1086{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001087 struct pcpes pcpes = {
1088 .pcrindex = pcrindex,
1089 .eventtype = EV_COMPACT_HASH,
1090 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001091 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001092
1093 if (is_preboot_if_shutdown() != 0)
1094 return TCG_INTERFACE_SHUTDOWN;
1095
Kevin O'Connor92244402015-11-22 16:54:18 -05001096 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001097 u32 rc = tpm_log_extend_event(&pcpes, &info);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001098 if (rc == 0)
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001099 *edx_ptr = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001100
1101 return rc;
1102}
1103
1104void VISIBLE32FLAT
1105tpm_interrupt_handler32(struct bregs *regs)
1106{
1107 if (!CONFIG_TCGBIOS)
1108 return;
1109
1110 set_cf(regs, 0);
1111
1112 if (!has_working_tpm()) {
1113 regs->eax = TCG_GENERAL_ERROR;
1114 return;
1115 }
1116
1117 switch ((enum irq_ids)regs->al) {
1118 case TCG_StatusCheck:
1119 if (is_tpm_present() == 0) {
1120 /* no TPM available */
1121 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1122 } else {
1123 regs->eax = 0;
1124 regs->ebx = TCG_MAGIC;
1125 regs->ch = TCG_VERSION_MAJOR;
1126 regs->cl = TCG_VERSION_MINOR;
1127 regs->edx = 0x0;
1128 regs->esi = (u32)tpm_state.log_area_start_address;
1129 regs->edi = (u32)tpm_state.log_area_last_entry;
1130 }
1131 break;
1132
1133 case TCG_HashLogExtendEvent:
1134 regs->eax =
1135 hash_log_extend_event_int(
1136 (struct hleei_short *)input_buf32(regs),
1137 (struct hleeo *)output_buf32(regs));
1138 break;
1139
1140 case TCG_PassThroughToTPM:
1141 regs->eax =
1142 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1143 (struct pttto *)output_buf32(regs));
1144 break;
1145
1146 case TCG_ShutdownPreBootInterface:
1147 regs->eax = shutdown_preboot_interface();
1148 break;
1149
1150 case TCG_HashLogEvent:
1151 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1152 (struct hleo*)output_buf32(regs));
1153 break;
1154
1155 case TCG_HashAll:
1156 regs->eax =
1157 hash_all_int((struct hai*)input_buf32(regs),
1158 (u8 *)output_buf32(regs));
1159 break;
1160
1161 case TCG_TSS:
1162 regs->eax = tss_int((struct ti*)input_buf32(regs),
1163 (struct to*)output_buf32(regs));
1164 break;
1165
1166 case TCG_CompactHashLogExtendEvent:
1167 regs->eax =
1168 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1169 regs->esi,
1170 regs->ecx,
1171 regs->edx,
1172 &regs->edx);
1173 break;
1174
1175 default:
1176 set_cf(regs, 1);
1177 }
1178
1179 return;
1180}