blob: c4e3b5ed4bddb82159b48678ba9b235211e4e76a [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
12
13#include "config.h"
14
15#include "types.h"
16#include "byteorder.h" // cpu_to_*
17#include "hw/tpm_drivers.h" // tpm_drivers[]
18#include "farptr.h" // MAKE_FLATPTR
19#include "string.h" // checksum
20#include "tcgbios.h"// tpm_*, prototypes
21#include "util.h" // printf, get_keystroke
22#include "output.h" // dprintf
23#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
24#include "bregs.h" // struct bregs
Stefan Berger5aa2a752015-03-23 14:22:17 -040025#include "sha1.h" // sha1
Quan Xu67643952015-04-30 19:43:04 -040026#include "fw/paravirt.h" // runningOnXen
Stefan Berger2aff1c12015-05-26 15:48:33 -040027#include "std/smbios.h"
Stefan Bergerb310dfa2015-03-23 14:22:16 -040028
Stefan Berger0d289b52015-06-09 19:56:29 -040029static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
30static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040031
Stefan Berger0d289b52015-06-09 19:56:29 -040032static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
33static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
34static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
35static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040036
37static const u8 CommandFlag_FALSE[1] = { 0x00 };
38static const u8 CommandFlag_TRUE[1] = { 0x01 };
39
Stefan Berger0d289b52015-06-09 19:56:29 -040040static const u8 GetCapability_Permanent_Flags[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040041 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
42 0x00, 0x00, 0x01, 0x08
43};
44
Stefan Berger0d289b52015-06-09 19:56:29 -040045static const u8 GetCapability_OwnerAuth[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040046 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
47 0x00, 0x00, 0x01, 0x11
48};
49
50static const u8 GetCapability_Timeouts[] = {
51 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
52 0x00, 0x00, 0x01, 0x15
53};
54
55static const u8 GetCapability_Durations[] = {
56 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
57 0x00, 0x00, 0x01, 0x20
58};
59
Stefan Berger2aff1c12015-05-26 15:48:33 -040060static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
61
Stefan Bergerb310dfa2015-03-23 14:22:16 -040062
63#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr)
64
Stefan Berger2aff1c12015-05-26 15:48:33 -040065/* local function prototypes */
66
Stefan Berger7fce1d92015-11-12 10:14:45 -050067static u32 build_and_send_cmd(u8 locty, u32 ordinal,
68 const u8 *append, u32 append_size,
69 u8 *resbuffer, u32 return_size, u32 *returnCode,
70 enum tpmDurationType to_t);
Stefan Berger2aff1c12015-05-26 15:48:33 -040071static u32 tpm_calling_int19h(void);
72static u32 tpm_add_event_separators(void);
73static u32 tpm_start_option_rom_scan(void);
74static u32 tpm_smbios_measure(void);
Stefan Bergerb310dfa2015-03-23 14:22:16 -040075
76/* helper functions */
77
78static inline void *input_buf32(struct bregs *regs)
79{
80 return MAKE_FLATPTR(regs->es, regs->di);
81}
82
83static inline void *output_buf32(struct bregs *regs)
84{
85 return MAKE_FLATPTR(regs->ds, regs->si);
86}
87
88
89typedef struct {
90 u8 tpm_probed:1;
91 u8 tpm_found:1;
92 u8 tpm_working:1;
93 u8 if_shutdown:1;
94 u8 tpm_driver_to_use:4;
95} tpm_state_t;
96
97
98static tpm_state_t tpm_state = {
99 .tpm_driver_to_use = TPM_INVALID_DRIVER,
100};
101
102
103/********************************************************
104 Extensions for TCG-enabled BIOS
105 *******************************************************/
106
107
108static u32
109is_tpm_present(void)
110{
111 u32 rc = 0;
112 unsigned int i;
113
114 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
115 struct tpm_driver *td = &tpm_drivers[i];
116 if (td->probe() != 0) {
117 td->init();
118 tpm_state.tpm_driver_to_use = i;
119 rc = 1;
120 break;
121 }
122 }
123
124 return rc;
125}
126
127static void
128probe_tpm(void)
129{
130 if (!tpm_state.tpm_probed) {
131 tpm_state.tpm_probed = 1;
132 tpm_state.tpm_found = (is_tpm_present() != 0);
133 tpm_state.tpm_working = tpm_state.tpm_found;
134 }
135}
136
137static int
138has_working_tpm(void)
139{
140 probe_tpm();
141
142 return tpm_state.tpm_working;
143}
144
Stefan Berger7fce1d92015-11-12 10:14:45 -0500145static void
146tpm_set_failure(void)
147{
148 u32 returnCode;
149
150 /* we will try to deactivate the TPM now - ignoring all errors */
151 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
152 PhysicalPresence_CMD_ENABLE,
153 sizeof(PhysicalPresence_CMD_ENABLE),
154 NULL, 0, &returnCode,
155 TPM_DURATION_TYPE_SHORT);
156
157 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
158 PhysicalPresence_PRESENT,
159 sizeof(PhysicalPresence_PRESENT),
160 NULL, 0, &returnCode,
161 TPM_DURATION_TYPE_SHORT);
162
163 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
164 NULL, 0, NULL, 0, &returnCode,
165 TPM_DURATION_TYPE_SHORT);
166
167 tpm_state.tpm_working = 0;
168}
169
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400170static struct tcpa_descriptor_rev2 *
171find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
172{
173 u32 ctr = 0;
174 struct tcpa_descriptor_rev2 *tcpa = NULL;
175 struct rsdt_descriptor *rsdt;
176 u32 length;
177 u16 off;
178
179 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
180 if (!rsdt)
181 return NULL;
182
183 length = rsdt->length;
184 off = offsetof(struct rsdt_descriptor, entry);
185
186 while ((off + sizeof(rsdt->entry[0])) <= length) {
187 /* try all pointers to structures */
188 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
189
190 /* valid TCPA ACPI table ? */
191 if (tcpa->signature == TCPA_SIGNATURE &&
192 checksum((u8 *)tcpa, tcpa->length) == 0)
193 break;
194
195 tcpa = NULL;
196 off += sizeof(rsdt->entry[0]);
197 ctr++;
198 }
199
200 return tcpa;
201}
202
203
204static struct tcpa_descriptor_rev2 *
205find_tcpa_table(void)
206{
207 struct tcpa_descriptor_rev2 *tcpa = NULL;
208 struct rsdp_descriptor *rsdp = RsdpAddr;
209
210 if (rsdp)
211 tcpa = find_tcpa_by_rsdp(rsdp);
212 else
213 tpm_state.if_shutdown = 1;
214
215 if (!rsdp)
216 dprintf(DEBUG_tcg,
217 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
218 else if (!tcpa)
219 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
220
221 return tcpa;
222}
223
224
225static u8 *
226get_lasa_base_ptr(u32 *log_area_minimum_length)
227{
228 u8 *log_area_start_address = 0;
229 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
230
231 if (tcpa) {
232 log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
233 if (log_area_minimum_length)
234 *log_area_minimum_length = tcpa->log_area_minimum_length;
235 }
236
237 return log_area_start_address;
238}
239
240
241/* clear the ACPI log */
242static void
243reset_acpi_log(void)
244{
245 u32 log_area_minimum_length;
246 u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
247
248 if (log_area_start_address)
249 memset(log_area_start_address, 0x0, log_area_minimum_length);
250}
251
252
253/*
254 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
255 where the TCPA table is.
256 */
257static void
258tpm_acpi_init(void)
259{
260 tpm_state.if_shutdown = 0;
261 tpm_state.tpm_probed = 0;
262 tpm_state.tpm_found = 0;
263 tpm_state.tpm_working = 0;
264
265 if (!has_working_tpm()) {
266 tpm_state.if_shutdown = 1;
267 return;
268 }
269
270 reset_acpi_log();
271}
272
273
274static u32
275transmit(u8 locty, const struct iovec iovec[],
276 u8 *respbuffer, u32 *respbufferlen,
277 enum tpmDurationType to_t)
278{
279 u32 rc = 0;
280 u32 irc;
281 struct tpm_driver *td;
282 unsigned int i;
283
284 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
285 return TCG_FATAL_COM_ERROR;
286
287 td = &tpm_drivers[tpm_state.tpm_driver_to_use];
288
289 irc = td->activate(locty);
290 if (irc != 0) {
291 /* tpm could not be activated */
292 return TCG_FATAL_COM_ERROR;
293 }
294
295 for (i = 0; iovec[i].length; i++) {
296 irc = td->senddata(iovec[i].data,
297 iovec[i].length);
298 if (irc != 0)
299 return TCG_FATAL_COM_ERROR;
300 }
301
302 irc = td->waitdatavalid();
303 if (irc != 0)
304 return TCG_FATAL_COM_ERROR;
305
306 irc = td->waitrespready(to_t);
307 if (irc != 0)
308 return TCG_FATAL_COM_ERROR;
309
310 irc = td->readresp(respbuffer,
311 respbufferlen);
312 if (irc != 0)
313 return TCG_FATAL_COM_ERROR;
314
315 td->ready();
316
317 return rc;
318}
319
320
321/*
322 * Send a TPM command with the given ordinal. Append the given buffer
323 * containing all data in network byte order to the command (this is
324 * the custom part per command) and expect a response of the given size.
325 * If a buffer is provided, the response will be copied into it.
326 */
327static u32
Stefan Berger5aa2a752015-03-23 14:22:17 -0400328build_and_send_cmd_od(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400329 u8 *resbuffer, u32 return_size, u32 *returnCode,
330 const u8 *otherdata, u32 otherdata_size,
331 enum tpmDurationType to_t)
332{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400333 u32 rc;
Stefan Bergerece25612015-11-12 10:14:46 -0500334 u8 obuffer[64];
335 struct tpm_req_header trqh;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400336 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerece25612015-11-12 10:14:46 -0500337 struct iovec iovec[4] = {{ 0 }};
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400338 u32 obuffer_len = sizeof(obuffer);
339 u32 idx = 1;
340
Stefan Bergerece25612015-11-12 10:14:46 -0500341 if (return_size > sizeof(obuffer)) {
342 dprintf(DEBUG_tcg, "TCGBIOS: size of requested response too big.");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400343 return TCG_FIRMWARE_ERROR;
344 }
345
Stefan Bergerece25612015-11-12 10:14:46 -0500346 trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
347 trqh.totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size +
348 otherdata_size);
349 trqh.ordinal = cpu_to_be32(ordinal);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400350
Stefan Bergerece25612015-11-12 10:14:46 -0500351 iovec[0].data = &trqh;
352 iovec[0].length = TPM_REQ_HEADER_SIZE;
353
354 if (append_size) {
355 iovec[1].data = append;
356 iovec[1].length = append_size;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400357 idx = 2;
358 }
359
Stefan Bergerece25612015-11-12 10:14:46 -0500360 if (otherdata) {
361 iovec[idx].data = (void *)otherdata;
362 iovec[idx].length = otherdata_size;
363 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400364
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400365 memset(obuffer, 0x0, sizeof(obuffer));
366
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400367 rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
368 if (rc)
369 return rc;
370
371 *returnCode = be32_to_cpu(trsh->errcode);
372
373 if (resbuffer)
374 memcpy(resbuffer, trsh, return_size);
375
376 return 0;
377}
378
379
380static u32
Stefan Berger5aa2a752015-03-23 14:22:17 -0400381build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400382 u8 *resbuffer, u32 return_size, u32 *returnCode,
383 enum tpmDurationType to_t)
384{
Stefan Berger5aa2a752015-03-23 14:22:17 -0400385 return build_and_send_cmd_od(locty, ordinal, append, append_size,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400386 resbuffer, return_size, returnCode,
387 NULL, 0, to_t);
388}
389
390
391static u32
392determine_timeouts(void)
393{
394 u32 rc;
395 u32 returnCode;
396 struct tpm_res_getcap_timeouts timeouts;
397 struct tpm_res_getcap_durations durations;
398 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
399 u32 i;
400
Stefan Berger5aa2a752015-03-23 14:22:17 -0400401 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400402 GetCapability_Timeouts,
403 sizeof(GetCapability_Timeouts),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400404 (u8 *)&timeouts, sizeof(timeouts),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400405 &returnCode, TPM_DURATION_TYPE_SHORT);
406
407 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
408 " = 0x%08x\n", returnCode);
409
410 if (rc || returnCode)
411 goto err_exit;
412
Stefan Berger5aa2a752015-03-23 14:22:17 -0400413 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400414 GetCapability_Durations,
415 sizeof(GetCapability_Durations),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400416 (u8 *)&durations, sizeof(durations),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400417 &returnCode, TPM_DURATION_TYPE_SHORT);
418
419 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
420 " = 0x%08x\n", returnCode);
421
422 if (rc || returnCode)
423 goto err_exit;
424
425 for (i = 0; i < 3; i++)
426 durations.durations[i] = be32_to_cpu(durations.durations[i]);
427
428 for (i = 0; i < 4; i++)
429 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
430
431 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
432 timeouts.timeouts[0],
433 timeouts.timeouts[1],
434 timeouts.timeouts[2],
435 timeouts.timeouts[3]);
436
437 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
438 durations.durations[0],
439 durations.durations[1],
440 durations.durations[2]);
441
442
443 td->set_timeouts(timeouts.timeouts, durations.durations);
444
445 return 0;
446
447err_exit:
448 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
449
Stefan Berger7fce1d92015-11-12 10:14:45 -0500450 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400451 if (rc)
452 return rc;
453 return TCG_TCG_COMMAND_ERROR;
454}
455
456
457static u32
458tpm_startup(void)
459{
460 u32 rc;
461 u32 returnCode;
462
463 if (!has_working_tpm())
464 return TCG_GENERAL_ERROR;
465
466 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400467 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400468 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400469 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400470
471 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
472 returnCode);
473
474 if (CONFIG_COREBOOT) {
475 /* with other firmware on the system the TPM may already have been
476 * initialized
477 */
478 if (returnCode == TPM_INVALID_POSTINIT)
479 returnCode = 0;
480 }
481
482 if (rc || returnCode)
483 goto err_exit;
484
Stefan Berger5aa2a752015-03-23 14:22:17 -0400485 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400486 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400487
488 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
489 returnCode);
490
491 if (rc || returnCode)
492 goto err_exit;
493
Stefan Berger5aa2a752015-03-23 14:22:17 -0400494 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400495 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400496
497 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
498 returnCode);
499
500 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
501 goto err_exit;
502
503 rc = determine_timeouts();
504 if (rc)
505 goto err_exit;
506
Stefan Berger2aff1c12015-05-26 15:48:33 -0400507 rc = tpm_smbios_measure();
508 if (rc)
509 goto err_exit;
510
511 rc = tpm_start_option_rom_scan();
512 if (rc)
513 goto err_exit;
514
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400515 return 0;
516
517err_exit:
518 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
519
Stefan Berger7fce1d92015-11-12 10:14:45 -0500520 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400521 if (rc)
522 return rc;
523 return TCG_TCG_COMMAND_ERROR;
524}
525
526
Kevin O'Connord6aca442015-06-10 11:00:17 -0400527void
528tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400529{
530 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400531 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400532
533 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400534 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400535 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400536
Kevin O'Connord6aca442015-06-10 11:00:17 -0400537 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400538}
539
540
Kevin O'Connord6aca442015-06-10 11:00:17 -0400541void
542tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400543{
544 u32 rc;
545 u32 returnCode;
546
547 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400548 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400549
550 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400551 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400552
Stefan Berger5aa2a752015-03-23 14:22:17 -0400553 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400554 PhysicalPresence_CMD_ENABLE,
555 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400556 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400557 if (rc || returnCode)
558 goto err_exit;
559
Stefan Berger5aa2a752015-03-23 14:22:17 -0400560 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400561 PhysicalPresence_NOT_PRESENT_LOCK,
562 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400563 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400564 if (rc || returnCode)
565 goto err_exit;
566
Stefan Berger2aff1c12015-05-26 15:48:33 -0400567 rc = tpm_calling_int19h();
568 if (rc)
569 goto err_exit;
570
571 rc = tpm_add_event_separators();
572 if (rc)
573 goto err_exit;
574
Kevin O'Connord6aca442015-06-10 11:00:17 -0400575 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400576
577err_exit:
578 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
579
Stefan Berger7fce1d92015-11-12 10:14:45 -0500580 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400581}
582
Stefan Berger5aa2a752015-03-23 14:22:17 -0400583static int
584is_valid_pcpes(struct pcpes *pcpes)
585{
586 return (pcpes->eventtype != 0);
587}
588
589
590static u8 *
591get_lasa_last_ptr(u16 *entry_count, u8 **log_area_start_address_next)
592{
593 struct pcpes *pcpes;
594 u32 log_area_minimum_length = 0;
595 u8 *log_area_start_address_base =
596 get_lasa_base_ptr(&log_area_minimum_length);
597 u8 *log_area_start_address_last = NULL;
598 u8 *end = log_area_start_address_base + log_area_minimum_length;
599 u32 size;
600
601 if (entry_count)
602 *entry_count = 0;
603
604 if (!log_area_start_address_base)
605 return NULL;
606
607 while (log_area_start_address_base < end) {
608 pcpes = (struct pcpes *)log_area_start_address_base;
609 if (!is_valid_pcpes(pcpes))
610 break;
611 if (entry_count)
612 (*entry_count)++;
613 size = pcpes->eventdatasize + offsetof(struct pcpes, event);
614 log_area_start_address_last = log_area_start_address_base;
615 log_area_start_address_base += size;
616 }
617
618 if (log_area_start_address_next)
619 *log_area_start_address_next = log_area_start_address_base;
620
621 return log_area_start_address_last;
622}
623
624
625static u32
626tpm_sha1_calc(const u8 *data, u32 length, u8 *hash)
627{
628 u32 rc;
629 u32 returnCode;
630 struct tpm_res_sha1start start;
631 struct tpm_res_sha1complete complete;
632 u32 blocks = length / 64;
633 u32 rest = length & 0x3f;
634 u32 numbytes, numbytes_no;
635 u32 offset = 0;
636
637 rc = build_and_send_cmd(0, TPM_ORD_SHA1Start,
638 NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400639 (u8 *)&start, sizeof(start),
Stefan Berger5aa2a752015-03-23 14:22:17 -0400640 &returnCode, TPM_DURATION_TYPE_SHORT);
641
642 if (rc || returnCode)
643 goto err_exit;
644
645 while (blocks > 0) {
646
647 numbytes = be32_to_cpu(start.max_num_bytes);
648 if (numbytes > blocks * 64)
649 numbytes = blocks * 64;
650
651 numbytes_no = cpu_to_be32(numbytes);
652
653 rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Update,
654 (u8 *)&numbytes_no, sizeof(numbytes_no),
655 NULL, 0, &returnCode,
656 &data[offset], numbytes,
657 TPM_DURATION_TYPE_SHORT);
658
659 if (rc || returnCode)
660 goto err_exit;
661
662 offset += numbytes;
663 blocks -= (numbytes / 64);
664 }
665
666 numbytes_no = cpu_to_be32(rest);
667
668 rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Complete,
669 (u8 *)&numbytes_no, sizeof(numbytes_no),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400670 (u8 *)&complete, sizeof(complete),
Stefan Berger5aa2a752015-03-23 14:22:17 -0400671 &returnCode,
672 &data[offset], rest, TPM_DURATION_TYPE_SHORT);
673
674 if (rc || returnCode)
675 goto err_exit;
676
677 memcpy(hash, complete.hash, sizeof(complete.hash));
678
679 return 0;
680
681err_exit:
682 dprintf(DEBUG_tcg, "TCGBIOS: TPM SHA1 malfunctioning.\n");
683
Stefan Berger7fce1d92015-11-12 10:14:45 -0500684 tpm_set_failure();
Stefan Berger5aa2a752015-03-23 14:22:17 -0400685 if (rc)
686 return rc;
687 return TCG_TCG_COMMAND_ERROR;
688}
689
690
691static u32
692sha1_calc(const u8 *data, u32 length, u8 *hash)
693{
694 if (length < tpm_drivers[tpm_state.tpm_driver_to_use].sha1threshold)
695 return tpm_sha1_calc(data, length, hash);
696
697 return sha1(data, length, hash);
698}
699
700
701/*
702 * Extend the ACPI log with the given entry by copying the
703 * entry data into the log.
704 * Input
Stefan Bergere3cc6322015-11-12 10:14:47 -0500705 * pcpes : Pointer to the event 'header' to be copied into the log
706 * event : Pointer to the event 'body' to be copied into the log
707 * event_length: Length of the event array
708 * entry_count : optional pointer to get the current entry count
Stefan Berger5aa2a752015-03-23 14:22:17 -0400709 *
710 * Output:
Stefan Bergere3cc6322015-11-12 10:14:47 -0500711 * Returns an error code in case of faiure, 0 in case of success
Stefan Berger5aa2a752015-03-23 14:22:17 -0400712 */
713static u32
Stefan Bergere3cc6322015-11-12 10:14:47 -0500714tpm_extend_acpi_log(struct pcpes *pcpes,
715 const char *event, u32 event_length,
716 u16 *entry_count)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400717{
718 u32 log_area_minimum_length, size;
719 u8 *log_area_start_address_base =
720 get_lasa_base_ptr(&log_area_minimum_length);
721 u8 *log_area_start_address_next = NULL;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400722
Stefan Berger7fce1d92015-11-12 10:14:45 -0500723 if (!has_working_tpm())
724 return TCG_GENERAL_ERROR;
725
Stefan Berger5aa2a752015-03-23 14:22:17 -0400726 get_lasa_last_ptr(entry_count, &log_area_start_address_next);
727
728 dprintf(DEBUG_tcg, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n",
729 log_area_start_address_base, log_area_start_address_next);
730
Stefan Berger7fce1d92015-11-12 10:14:45 -0500731 if (log_area_start_address_next == NULL || log_area_minimum_length == 0) {
732 tpm_set_failure();
733
Stefan Berger5aa2a752015-03-23 14:22:17 -0400734 return TCG_PC_LOGOVERFLOW;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500735 }
Stefan Berger5aa2a752015-03-23 14:22:17 -0400736
Stefan Bergere3cc6322015-11-12 10:14:47 -0500737 size = offsetof(struct pcpes, event) + event_length;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400738
739 if ((log_area_start_address_next + size - log_area_start_address_base) >
740 log_area_minimum_length) {
741 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Stefan Berger7fce1d92015-11-12 10:14:45 -0500742
743 tpm_set_failure();
744
Stefan Berger5aa2a752015-03-23 14:22:17 -0400745 return TCG_PC_LOGOVERFLOW;
746 }
747
Stefan Bergere3cc6322015-11-12 10:14:47 -0500748 pcpes->eventdatasize = event_length;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400749
Stefan Bergere3cc6322015-11-12 10:14:47 -0500750 memcpy(log_area_start_address_next, pcpes, offsetof(struct pcpes, event));
751 memcpy(log_area_start_address_next + offsetof(struct pcpes, event),
752 event, event_length);
753
754 if (entry_count)
755 (*entry_count)++;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400756
757 return 0;
758}
759
760
761static u32
762is_preboot_if_shutdown(void)
763{
764 return tpm_state.if_shutdown;
765}
766
767
768static u32
769shutdown_preboot_interface(void)
770{
771 u32 rc = 0;
772
773 if (!is_preboot_if_shutdown()) {
774 tpm_state.if_shutdown = 1;
775 } else {
776 rc = TCG_INTERFACE_SHUTDOWN;
777 }
778
779 return rc;
780}
781
782
783static void
784tpm_shutdown(void)
785{
786 reset_acpi_log();
787 shutdown_preboot_interface();
788}
789
790
791static u32
792pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
793{
794 u32 rc = 0;
795 u32 resbuflen = 0;
796 struct tpm_req_header *trh;
797 u8 locty = 0;
798 struct iovec iovec[2];
799 const u32 *tmp;
800
801 if (is_preboot_if_shutdown()) {
802 rc = TCG_INTERFACE_SHUTDOWN;
803 goto err_exit;
804 }
805
806 trh = (struct tpm_req_header *)pttti->tpmopin;
807
808 if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
809 pttti->opblength < sizeof(struct pttto) ||
810 be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) {
811 rc = TCG_INVALID_INPUT_PARA;
812 goto err_exit;
813 }
814
815 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
816
817 iovec[0].data = pttti->tpmopin;
818 tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
819 iovec[0].length = cpu_to_be32(*tmp);
820
821 iovec[1].data = NULL;
822 iovec[1].length = 0;
823
824 rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen,
825 TPM_DURATION_TYPE_LONG /* worst case */);
826 if (rc)
827 goto err_exit;
828
829 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
830 pttto->reserved = 0;
831
832err_exit:
833 if (rc != 0) {
834 pttto->opblength = 4;
835 pttto->reserved = 0;
836 }
837
838 return rc;
839}
840
841
842static u32
843tpm_extend(u8 *hash, u32 pcrindex)
844{
845 u32 rc;
846 struct pttto_extend pttto;
847 struct pttti_extend pttti = {
848 .pttti = {
849 .ipblength = sizeof(struct pttti_extend),
850 .opblength = sizeof(struct pttto_extend),
851 },
852 .req = {
853 .tag = cpu_to_be16(0xc1),
854 .totlen = cpu_to_be32(sizeof(pttti.req)),
855 .ordinal = cpu_to_be32(TPM_ORD_Extend),
856 .pcrindex = cpu_to_be32(pcrindex),
857 },
858 };
859
860 memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
861
862 rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
863
864 if (rc == 0) {
865 if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE ||
866 pttto.pttto.opblength !=
867 sizeof(struct pttto) + be32_to_cpu(pttto.rsp.totlen) ||
868 be16_to_cpu(pttto.rsp.tag) != 0xc4) {
869 rc = TCG_FATAL_COM_ERROR;
870 }
871 }
872
873 if (rc)
874 tpm_shutdown();
875
876 return rc;
877}
878
879
880static u32
881hash_all(const struct hai *hai, u8 *hash)
882{
883 if (is_preboot_if_shutdown() != 0)
884 return TCG_INTERFACE_SHUTDOWN;
885
886 if (hai->ipblength != sizeof(struct hai) ||
887 hai->hashdataptr == 0 ||
888 hai->hashdatalen == 0 ||
889 hai->algorithmid != TPM_ALG_SHA)
890 return TCG_INVALID_INPUT_PARA;
891
892 return sha1_calc((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
893}
894
Stefan Berger129c04b2015-11-12 10:14:48 -0500895static u32
896hash_log_event(const void *hashdata, u32 hashdata_length,
897 struct pcpes *pcpes,
898 const char *event, u32 event_length,
899 u16 *entry_count)
900{
901 u32 rc = 0;
902
903 if (pcpes->pcrindex >= 24)
904 return TCG_INVALID_INPUT_PARA;
905
906 if (hashdata) {
907 rc = sha1_calc(hashdata, hashdata_length, pcpes->digest);
908 if (rc)
909 return rc;
910 }
911
912 return tpm_extend_acpi_log(pcpes, event, event_length, entry_count);
913}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400914
915static u32
Stefan Berger129c04b2015-11-12 10:14:48 -0500916hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400917{
918 u32 rc = 0;
919 u16 size;
920 struct pcpes *pcpes;
921 u16 entry_count;
922
923 if (is_preboot_if_shutdown() != 0) {
924 rc = TCG_INTERFACE_SHUTDOWN;
925 goto err_exit;
926 }
927
928 size = hlei->ipblength;
929 if (size != sizeof(*hlei)) {
930 rc = TCG_INVALID_INPUT_PARA;
931 goto err_exit;
932 }
933
934 pcpes = (struct pcpes *)hlei->logdataptr;
935
936 if (pcpes->pcrindex >= 24 ||
937 pcpes->pcrindex != hlei->pcrindex ||
Stefan Berger129c04b2015-11-12 10:14:48 -0500938 pcpes->eventtype != hlei->logeventtype ||
939 hlei->logdatalen !=
940 offsetof(struct pcpes, event) + pcpes->eventdatasize) {
Stefan Berger5aa2a752015-03-23 14:22:17 -0400941 rc = TCG_INVALID_INPUT_PARA;
942 goto err_exit;
943 }
944
Stefan Berger129c04b2015-11-12 10:14:48 -0500945 rc = hash_log_event(hlei->hashdataptr, hlei->hashdatalen,
946 pcpes, (char *)&pcpes->event, pcpes->eventdatasize,
947 &entry_count);
Stefan Berger5aa2a752015-03-23 14:22:17 -0400948 if (rc)
949 goto err_exit;
950
951 /* updating the log was fine */
952 hleo->opblength = sizeof(struct hleo);
953 hleo->reserved = 0;
954 hleo->eventnumber = entry_count;
955
956err_exit:
957 if (rc != 0) {
958 hleo->opblength = 2;
959 hleo->reserved = 0;
960 }
961
962 return rc;
963}
964
Stefan Berger6c376b42015-11-12 10:14:49 -0500965static u32
966hash_log_extend_event(const void *hashdata, u32 hashdata_length,
967 struct pcpes *pcpes,
968 const char *event, u32 event_length,
969 u32 pcrindex, u16 *entry_count)
970{
971 u32 rc;
972
973 rc = hash_log_event(hashdata, hashdata_length, pcpes,
974 event, event_length, entry_count);
975 if (rc)
976 return rc;
977
978 return tpm_extend(pcpes->digest, pcrindex);
979}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400980
981static u32
Stefan Berger6c376b42015-11-12 10:14:49 -0500982hash_log_extend_event_int(const struct hleei_short *hleei_s,
983 struct hleeo *hleeo)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400984{
985 u32 rc = 0;
986 struct hleo hleo;
987 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
988 const void *logdataptr;
989 u32 logdatalen;
990 struct pcpes *pcpes;
Stefan Berger6c376b42015-11-12 10:14:49 -0500991 u32 pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400992
993 /* short or long version? */
994 switch (hleei_s->ipblength) {
995 case sizeof(struct hleei_short):
996 /* short */
997 logdataptr = hleei_s->logdataptr;
998 logdatalen = hleei_s->logdatalen;
Stefan Berger6c376b42015-11-12 10:14:49 -0500999 pcrindex = hleei_s->pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001000 break;
1001
1002 case sizeof(struct hleei_long):
1003 /* long */
1004 logdataptr = hleei_l->logdataptr;
1005 logdatalen = hleei_l->logdatalen;
Stefan Berger6c376b42015-11-12 10:14:49 -05001006 pcrindex = hleei_l->pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001007 break;
1008
1009 default:
1010 /* bad input block */
1011 rc = TCG_INVALID_INPUT_PARA;
1012 goto err_exit;
1013 }
1014
1015 pcpes = (struct pcpes *)logdataptr;
1016
Stefan Berger6c376b42015-11-12 10:14:49 -05001017 if (pcpes->pcrindex >= 24 ||
1018 pcpes->pcrindex != pcrindex ||
1019 logdatalen != offsetof(struct pcpes, event) + pcpes->eventdatasize) {
1020 rc = TCG_INVALID_INPUT_PARA;
1021 goto err_exit;
1022 }
1023
1024 rc = hash_log_extend_event(hleei_s->hashdataptr, hleei_s->hashdatalen,
1025 pcpes,
1026 (char *)&pcpes->event, pcpes->eventdatasize,
1027 pcrindex, NULL);
Stefan Berger5aa2a752015-03-23 14:22:17 -04001028 if (rc)
1029 goto err_exit;
1030
1031 hleeo->opblength = sizeof(struct hleeo);
1032 hleeo->reserved = 0;
1033 hleeo->eventnumber = hleo.eventnumber;
1034
Stefan Berger5aa2a752015-03-23 14:22:17 -04001035err_exit:
1036 if (rc != 0) {
1037 hleeo->opblength = 4;
1038 hleeo->reserved = 0;
1039 }
1040
1041 return rc;
1042
1043}
1044
1045
1046static u32
1047tss(struct ti *ti, struct to *to)
1048{
1049 u32 rc = 0;
1050
1051 if (is_preboot_if_shutdown() == 0) {
1052 rc = TCG_PC_UNSUPPORTED;
1053 } else {
1054 rc = TCG_INTERFACE_SHUTDOWN;
1055 }
1056
1057 to->opblength = sizeof(struct to);
1058 to->reserved = 0;
1059
1060 return rc;
1061}
1062
1063
1064static u32
1065compact_hash_log_extend_event(u8 *buffer,
1066 u32 info,
1067 u32 length,
1068 u32 pcrindex,
1069 u32 *edx_ptr)
1070{
1071 u32 rc = 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001072 struct pcpes pcpes = {
1073 .pcrindex = pcrindex,
1074 .eventtype = EV_COMPACT_HASH,
1075 .eventdatasize = sizeof(info),
1076 .event = info,
1077 };
Stefan Berger6c376b42015-11-12 10:14:49 -05001078 u16 entry_count;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001079
Stefan Berger6c376b42015-11-12 10:14:49 -05001080 rc = hash_log_extend_event(buffer, length,
1081 &pcpes,
1082 (char *)&pcpes.event, pcpes.eventdatasize,
1083 pcpes.pcrindex, &entry_count);
1084
Stefan Berger5aa2a752015-03-23 14:22:17 -04001085 if (rc == 0)
Stefan Berger6c376b42015-11-12 10:14:49 -05001086 *edx_ptr = entry_count;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001087
1088 return rc;
1089}
1090
1091
1092void VISIBLE32FLAT
1093tpm_interrupt_handler32(struct bregs *regs)
1094{
1095 if (!CONFIG_TCGBIOS)
1096 return;
1097
1098 set_cf(regs, 0);
1099
1100 if (!has_working_tpm()) {
1101 regs->eax = TCG_GENERAL_ERROR;
1102 return;
1103 }
1104
1105 switch ((enum irq_ids)regs->al) {
1106 case TCG_StatusCheck:
1107 if (is_tpm_present() == 0) {
1108 /* no TPM available */
1109 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1110 } else {
1111 regs->eax = 0;
1112 regs->ebx = TCG_MAGIC;
1113 regs->ch = TCG_VERSION_MAJOR;
1114 regs->cl = TCG_VERSION_MINOR;
1115 regs->edx = 0x0;
1116 regs->esi = (u32)get_lasa_base_ptr(NULL);
1117 regs->edi =
1118 (u32)get_lasa_last_ptr(NULL, NULL);
1119 }
1120 break;
1121
1122 case TCG_HashLogExtendEvent:
1123 regs->eax =
Stefan Berger6c376b42015-11-12 10:14:49 -05001124 hash_log_extend_event_int(
Stefan Berger5aa2a752015-03-23 14:22:17 -04001125 (struct hleei_short *)input_buf32(regs),
1126 (struct hleeo *)output_buf32(regs));
1127 break;
1128
1129 case TCG_PassThroughToTPM:
1130 regs->eax =
1131 pass_through_to_tpm((struct pttti *)input_buf32(regs),
1132 (struct pttto *)output_buf32(regs));
1133 break;
1134
1135 case TCG_ShutdownPreBootInterface:
1136 regs->eax = shutdown_preboot_interface();
1137 break;
1138
1139 case TCG_HashLogEvent:
Stefan Berger129c04b2015-11-12 10:14:48 -05001140 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1141 (struct hleo*)output_buf32(regs));
Stefan Berger5aa2a752015-03-23 14:22:17 -04001142 break;
1143
1144 case TCG_HashAll:
1145 regs->eax =
1146 hash_all((struct hai*)input_buf32(regs),
1147 (u8 *)output_buf32(regs));
1148 break;
1149
1150 case TCG_TSS:
1151 regs->eax = tss((struct ti*)input_buf32(regs),
1152 (struct to*)output_buf32(regs));
1153 break;
1154
1155 case TCG_CompactHashLogExtendEvent:
1156 regs->eax =
1157 compact_hash_log_extend_event((u8 *)input_buf32(regs),
1158 regs->esi,
1159 regs->ecx,
1160 regs->edx,
1161 &regs->edx);
1162 break;
1163
1164 default:
1165 set_cf(regs, 1);
1166 }
1167
1168 return;
1169}
1170
Stefan Berger2aff1c12015-05-26 15:48:33 -04001171/*
1172 * Add a measurement to the log; the data at data_seg:data/length are
1173 * appended to the TCG_PCClientPCREventStruct
1174 *
1175 * Input parameters:
Stefan Berger6c376b42015-11-12 10:14:49 -05001176 * pcrindex : which PCR to extend
Stefan Berger2aff1c12015-05-26 15:48:33 -04001177 * event_type : type of event; specs section on 'Event Types'
Stefan Berger6c376b42015-11-12 10:14:49 -05001178 * event : pointer to info (e.g., string) to be added to log as-is
1179 * event_length: length of the event
1180 * hashdata : pointer to the data to be hashed
1181 * hashdata_length: length of the data to be hashed
Stefan Berger2aff1c12015-05-26 15:48:33 -04001182 */
1183static u32
Stefan Berger6c376b42015-11-12 10:14:49 -05001184tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
1185 const char *event, u32 event_length,
1186 const u8 *hashdata, u32 hashdata_length)
Stefan Berger2aff1c12015-05-26 15:48:33 -04001187{
Stefan Berger6c376b42015-11-12 10:14:49 -05001188 struct pcpes pcpes = {
1189 .pcrindex = pcrindex,
1190 .eventtype = event_type,
1191 };
1192 u16 entry_count;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001193
Stefan Berger6c376b42015-11-12 10:14:49 -05001194 return hash_log_extend_event(hashdata, hashdata_length, &pcpes,
1195 event, event_length, pcrindex,
1196 &entry_count);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001197}
1198
1199
1200/*
1201 * Add a measurement to the list of measurements
1202 * pcrIndex : PCR to be extended
1203 * event_type : type of event; specs section on 'Event Types'
1204 * data : additional parameter; used as parameter for
1205 * 'action index'
1206 */
1207static u32
1208tpm_add_measurement(u32 pcrIndex,
1209 u16 event_type,
1210 const char *string)
1211{
1212 u32 rc;
1213 u32 len;
1214
1215 switch (event_type) {
1216 case EV_SEPARATOR:
1217 len = sizeof(evt_separator);
1218 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1219 (char *)NULL, 0,
1220 (u8 *)evt_separator, len);
1221 break;
1222
1223 case EV_ACTION:
1224 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1225 string, strlen(string),
1226 (u8 *)string, strlen(string));
1227 break;
1228
1229 default:
1230 rc = TCG_INVALID_INPUT_PARA;
1231 }
1232
1233 return rc;
1234}
1235
1236
1237static u32
1238tpm_calling_int19h(void)
1239{
1240 if (!CONFIG_TCGBIOS)
1241 return 0;
1242
1243 if (!has_working_tpm())
1244 return TCG_GENERAL_ERROR;
1245
1246 return tpm_add_measurement(4, EV_ACTION,
1247 "Calling INT 19h");
1248}
1249
1250/*
1251 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
1252 */
1253u32
1254tpm_add_event_separators(void)
1255{
1256 u32 rc;
1257 u32 pcrIndex = 0;
1258
1259 if (!CONFIG_TCGBIOS)
1260 return 0;
1261
1262 if (!has_working_tpm())
1263 return TCG_GENERAL_ERROR;
1264
1265 while (pcrIndex <= 7) {
1266 rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
1267 if (rc)
1268 break;
1269 pcrIndex ++;
1270 }
1271
1272 return rc;
1273}
1274
1275
1276/*
1277 * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
1278 * the list of measurements.
1279 */
1280static u32
1281tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
1282{
1283 const char *string;
1284
1285 if (!CONFIG_TCGBIOS)
1286 return 0;
1287
1288 if (!has_working_tpm())
1289 return TCG_GENERAL_ERROR;
1290
1291 switch (bootcd) {
1292 case 0:
1293 switch (bootdrv) {
1294 case 0:
1295 string = "Booting BCV device 00h (Floppy)";
1296 break;
1297
1298 case 0x80:
1299 string = "Booting BCV device 80h (HDD)";
1300 break;
1301
1302 default:
1303 string = "Booting unknown device";
1304 break;
1305 }
1306
1307 break;
1308
1309 default:
1310 string = "Booting from CD ROM device";
1311 }
1312
1313 return tpm_add_measurement_to_log(4, EV_ACTION,
1314 string, strlen(string),
1315 (u8 *)string, strlen(string));
1316}
1317
1318
1319/*
1320 * Add measurement to the log about option rom scan
1321 */
1322u32
1323tpm_start_option_rom_scan(void)
1324{
1325 if (!CONFIG_TCGBIOS)
1326 return 0;
1327
1328 if (!has_working_tpm())
1329 return TCG_GENERAL_ERROR;
1330
1331 return tpm_add_measurement(2, EV_ACTION,
1332 "Start Option ROM Scan");
1333}
1334
1335
1336/*
1337 * Add measurement to the log about an option rom
1338 */
1339u32
1340tpm_option_rom(const void *addr, u32 len)
1341{
1342 if (!CONFIG_TCGBIOS)
1343 return 0;
1344
1345 if (!has_working_tpm())
1346 return TCG_GENERAL_ERROR;
1347
1348 u32 rc;
1349 struct pcctes_romex pcctes = {
1350 .eventid = 7,
1351 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
1352 };
1353
1354 rc = sha1((const u8 *)addr, len, pcctes.digest);
1355 if (rc)
1356 return rc;
1357
1358 return tpm_add_measurement_to_log(2,
1359 EV_EVENT_TAG,
1360 (const char *)&pcctes, sizeof(pcctes),
1361 (u8 *)&pcctes, sizeof(pcctes));
1362}
1363
1364
1365u32
1366tpm_smbios_measure(void)
1367{
1368 if (!CONFIG_TCGBIOS)
1369 return 0;
1370
1371 if (!has_working_tpm())
1372 return TCG_GENERAL_ERROR;
1373
1374 u32 rc;
1375 struct pcctes pcctes = {
1376 .eventid = 1,
1377 .eventdatasize = SHA1_BUFSIZE,
1378 };
1379 struct smbios_entry_point *sep = SMBiosAddr;
1380
1381 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
1382
1383 if (!sep)
1384 return 0;
1385
1386 rc = sha1((const u8 *)sep->structure_table_address,
1387 sep->structure_table_length, pcctes.digest);
1388 if (rc)
1389 return rc;
1390
1391 return tpm_add_measurement_to_log(1,
1392 EV_EVENT_TAG,
1393 (const char *)&pcctes, sizeof(pcctes),
1394 (u8 *)&pcctes, sizeof(pcctes));
1395}
1396
1397
1398/*
1399 * Add a measurement related to Initial Program Loader to the log.
1400 * Creates two log entries.
1401 *
1402 * Input parameter:
1403 * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
1404 * addr : address where the IP data are located
1405 * length : IP data length in bytes
1406 */
1407static u32
1408tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
1409{
1410 u32 rc;
1411 const char *string;
1412
1413 switch (bootcd) {
1414 case IPL_EL_TORITO_1:
1415 /* specs: see section 'El Torito' */
1416 string = "EL TORITO IPL";
1417 rc = tpm_add_measurement_to_log(4, EV_IPL,
1418 string, strlen(string),
1419 addr, length);
1420 break;
1421
1422 case IPL_EL_TORITO_2:
1423 /* specs: see section 'El Torito' */
1424 string = "BOOT CATALOG";
1425 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1426 string, strlen(string),
1427 addr, length);
1428 break;
1429
1430 default:
1431 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1432 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
1433 string = "MBR";
1434 rc = tpm_add_measurement_to_log(4, EV_IPL,
1435 string, strlen(string),
1436 addr, 0x1b8);
1437
1438 if (rc)
1439 break;
1440
1441 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
1442 string = "MBR PARTITION_TABLE";
1443 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1444 string, strlen(string),
1445 addr + 0x1b8, 0x48);
1446 }
1447
1448 return rc;
1449}
1450
1451u32
1452tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1453{
1454 if (!CONFIG_TCGBIOS)
1455 return 0;
1456
1457 if (!has_working_tpm())
1458 return TCG_GENERAL_ERROR;
1459
1460 u32 rc = tpm_add_bootdevice(0, bootdrv);
1461 if (rc)
1462 return rc;
1463
1464 return tpm_ipl(IPL_BCV, addr, length);
1465}
1466
1467u32
1468tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1469{
1470 if (!CONFIG_TCGBIOS)
1471 return 0;
1472
1473 if (!has_working_tpm())
1474 return TCG_GENERAL_ERROR;
1475
1476 u32 rc = tpm_add_bootdevice(1, bootdrv);
1477 if (rc)
1478 return rc;
1479
1480 return tpm_ipl(IPL_EL_TORITO_1, addr, length);
1481}
1482
1483u32
1484tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1485{
1486 if (!CONFIG_TCGBIOS)
1487 return 0;
1488
1489 if (!has_working_tpm())
1490 return TCG_GENERAL_ERROR;
1491
1492 u32 rc = tpm_add_bootdevice(1, 0);
1493 if (rc)
1494 return rc;
1495
1496 return tpm_ipl(IPL_EL_TORITO_2, addr, length);
1497}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001498
Kevin O'Connord6aca442015-06-10 11:00:17 -04001499void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001500tpm_s3_resume(void)
1501{
1502 u32 rc;
1503 u32 returnCode;
1504
1505 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001506 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001507
1508 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001509 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001510
1511 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1512
Stefan Berger5aa2a752015-03-23 14:22:17 -04001513 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001514 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -04001515 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001516
1517 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
1518 returnCode);
1519
1520 if (rc || returnCode)
1521 goto err_exit;
1522
Kevin O'Connord6aca442015-06-10 11:00:17 -04001523 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001524
1525err_exit:
1526 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1527
Stefan Berger7fce1d92015-11-12 10:14:45 -05001528 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001529}