blob: 018c58048c4435662cee538fa10cdb72a2f19113 [file] [log] [blame]
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001// Implementation of the TCG BIOS extension according to the specification
Stefan Berger2aff1c12015-05-26 15:48:33 -04002// described in specs found at
3// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
Stefan Bergerb310dfa2015-03-23 14:22:16 -04004//
Stefan Berger2aff1c12015-05-26 15:48:33 -04005// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
Stefan Bergerb310dfa2015-03-23 14:22:16 -04006//
7// Authors:
8// Stefan Berger <stefanb@linux.vnet.ibm.com>
9//
10// This file may be distributed under the terms of the GNU LGPLv3 license.
11
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050012#include "bregs.h" // struct bregs
Stefan Bergerb310dfa2015-03-23 14:22:16 -040013#include "byteorder.h" // cpu_to_*
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050014#include "config.h" // CONFIG_TCGBIOS
Stefan Bergerb310dfa2015-03-23 14:22:16 -040015#include "farptr.h" // MAKE_FLATPTR
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050016#include "fw/paravirt.h" // runningOnXen
17#include "hw/tpm_drivers.h" // tpm_drivers[]
18#include "output.h" // dprintf
19#include "sha1.h" // sha1
20#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
21#include "std/smbios.h" // struct smbios_entry_point
22#include "std/tcg.h" // TCG_PC_LOGOVERFLOW
Stefan Bergerb310dfa2015-03-23 14:22:16 -040023#include "string.h" // checksum
24#include "tcgbios.h"// tpm_*, prototypes
25#include "util.h" // printf, get_keystroke
Stefan Bergerb310dfa2015-03-23 14:22:16 -040026
Stefan Berger0d289b52015-06-09 19:56:29 -040027static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
28static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040029
Stefan Berger0d289b52015-06-09 19:56:29 -040030static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
31static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
32static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
33static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040034
35static const u8 CommandFlag_FALSE[1] = { 0x00 };
36static const u8 CommandFlag_TRUE[1] = { 0x01 };
37
Stefan Berger0d289b52015-06-09 19:56:29 -040038static const u8 GetCapability_Permanent_Flags[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040039 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
40 0x00, 0x00, 0x01, 0x08
41};
42
Stefan Berger0d289b52015-06-09 19:56:29 -040043static const u8 GetCapability_OwnerAuth[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040044 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
45 0x00, 0x00, 0x01, 0x11
46};
47
48static const u8 GetCapability_Timeouts[] = {
49 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
50 0x00, 0x00, 0x01, 0x15
51};
52
53static const u8 GetCapability_Durations[] = {
54 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
55 0x00, 0x00, 0x01, 0x20
56};
57
Stefan Berger2aff1c12015-05-26 15:48:33 -040058static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
59
Stefan Bergerb310dfa2015-03-23 14:22:16 -040060
61#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr)
62
Stefan Berger2aff1c12015-05-26 15:48:33 -040063/* local function prototypes */
64
Stefan Berger7fce1d92015-11-12 10:14:45 -050065static u32 build_and_send_cmd(u8 locty, u32 ordinal,
66 const u8 *append, u32 append_size,
67 u8 *resbuffer, u32 return_size, u32 *returnCode,
68 enum tpmDurationType to_t);
Stefan Berger2aff1c12015-05-26 15:48:33 -040069static u32 tpm_calling_int19h(void);
70static u32 tpm_add_event_separators(void);
71static u32 tpm_start_option_rom_scan(void);
72static u32 tpm_smbios_measure(void);
Stefan Bergerb310dfa2015-03-23 14:22:16 -040073
74/* helper functions */
75
76static inline void *input_buf32(struct bregs *regs)
77{
78 return MAKE_FLATPTR(regs->es, regs->di);
79}
80
81static inline void *output_buf32(struct bregs *regs)
82{
83 return MAKE_FLATPTR(regs->ds, regs->si);
84}
85
86
87typedef struct {
88 u8 tpm_probed:1;
89 u8 tpm_found:1;
90 u8 tpm_working:1;
91 u8 if_shutdown:1;
92 u8 tpm_driver_to_use:4;
Stefan Berger60bb9e92015-11-21 14:54:42 -050093 struct tcpa_descriptor_rev2 *tcpa;
94
95 /* length of the TCPA log buffer */
96 u32 log_area_minimum_length;
97
98 /* start address of TCPA log buffer */
99 u8 * log_area_start_address;
100
101 /* number of log entries written */
102 u32 entry_count;
103
104 /* address to write next log entry to */
105 u8 * log_area_next_entry;
106
107 /* address of last entry written (need for TCG_StatusCheck) */
108 u8 * log_area_last_entry;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400109} tpm_state_t;
110
111
Stefan Berger60bb9e92015-11-21 14:54:42 -0500112tpm_state_t tpm_state VARLOW = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400113 .tpm_driver_to_use = TPM_INVALID_DRIVER,
114};
115
116
117/********************************************************
118 Extensions for TCG-enabled BIOS
119 *******************************************************/
120
121
122static u32
123is_tpm_present(void)
124{
125 u32 rc = 0;
126 unsigned int i;
127
128 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
129 struct tpm_driver *td = &tpm_drivers[i];
130 if (td->probe() != 0) {
131 td->init();
132 tpm_state.tpm_driver_to_use = i;
133 rc = 1;
134 break;
135 }
136 }
137
138 return rc;
139}
140
141static void
142probe_tpm(void)
143{
144 if (!tpm_state.tpm_probed) {
145 tpm_state.tpm_probed = 1;
146 tpm_state.tpm_found = (is_tpm_present() != 0);
147 tpm_state.tpm_working = tpm_state.tpm_found;
148 }
149}
150
151static int
152has_working_tpm(void)
153{
154 probe_tpm();
155
156 return tpm_state.tpm_working;
157}
158
Stefan Berger7fce1d92015-11-12 10:14:45 -0500159static void
160tpm_set_failure(void)
161{
162 u32 returnCode;
163
164 /* we will try to deactivate the TPM now - ignoring all errors */
165 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
166 PhysicalPresence_CMD_ENABLE,
167 sizeof(PhysicalPresence_CMD_ENABLE),
168 NULL, 0, &returnCode,
169 TPM_DURATION_TYPE_SHORT);
170
171 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
172 PhysicalPresence_PRESENT,
173 sizeof(PhysicalPresence_PRESENT),
174 NULL, 0, &returnCode,
175 TPM_DURATION_TYPE_SHORT);
176
177 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
178 NULL, 0, NULL, 0, &returnCode,
179 TPM_DURATION_TYPE_SHORT);
180
181 tpm_state.tpm_working = 0;
182}
183
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400184static struct tcpa_descriptor_rev2 *
185find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
186{
187 u32 ctr = 0;
188 struct tcpa_descriptor_rev2 *tcpa = NULL;
189 struct rsdt_descriptor *rsdt;
190 u32 length;
191 u16 off;
192
193 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
194 if (!rsdt)
195 return NULL;
196
197 length = rsdt->length;
198 off = offsetof(struct rsdt_descriptor, entry);
199
200 while ((off + sizeof(rsdt->entry[0])) <= length) {
201 /* try all pointers to structures */
202 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
203
204 /* valid TCPA ACPI table ? */
205 if (tcpa->signature == TCPA_SIGNATURE &&
206 checksum((u8 *)tcpa, tcpa->length) == 0)
207 break;
208
209 tcpa = NULL;
210 off += sizeof(rsdt->entry[0]);
211 ctr++;
212 }
213
Stefan Berger60bb9e92015-11-21 14:54:42 -0500214 /* cache it */
215 if (tcpa)
216 tpm_state.tcpa = tcpa;
217
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400218 return tcpa;
219}
220
221
222static struct tcpa_descriptor_rev2 *
223find_tcpa_table(void)
224{
225 struct tcpa_descriptor_rev2 *tcpa = NULL;
226 struct rsdp_descriptor *rsdp = RsdpAddr;
227
Stefan Berger60bb9e92015-11-21 14:54:42 -0500228 if (tpm_state.tcpa)
229 return tpm_state.tcpa;
230
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400231 if (rsdp)
232 tcpa = find_tcpa_by_rsdp(rsdp);
233 else
234 tpm_state.if_shutdown = 1;
235
236 if (!rsdp)
237 dprintf(DEBUG_tcg,
238 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
239 else if (!tcpa)
240 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
241
242 return tcpa;
243}
244
245
246static u8 *
247get_lasa_base_ptr(u32 *log_area_minimum_length)
248{
249 u8 *log_area_start_address = 0;
250 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
251
252 if (tcpa) {
253 log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
254 if (log_area_minimum_length)
255 *log_area_minimum_length = tcpa->log_area_minimum_length;
256 }
257
258 return log_area_start_address;
259}
260
261
262/* clear the ACPI log */
263static void
264reset_acpi_log(void)
265{
Stefan Berger60bb9e92015-11-21 14:54:42 -0500266 tpm_state.log_area_start_address =
267 get_lasa_base_ptr(&tpm_state.log_area_minimum_length);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400268
Stefan Berger60bb9e92015-11-21 14:54:42 -0500269 if (tpm_state.log_area_start_address)
270 memset(tpm_state.log_area_start_address, 0,
271 tpm_state.log_area_minimum_length);
272
273 tpm_state.log_area_next_entry = tpm_state.log_area_start_address;
274 tpm_state.log_area_last_entry = NULL;
275 tpm_state.entry_count = 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400276}
277
278
279/*
280 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
281 where the TCPA table is.
282 */
283static void
284tpm_acpi_init(void)
285{
286 tpm_state.if_shutdown = 0;
287 tpm_state.tpm_probed = 0;
288 tpm_state.tpm_found = 0;
289 tpm_state.tpm_working = 0;
290
291 if (!has_working_tpm()) {
292 tpm_state.if_shutdown = 1;
293 return;
294 }
295
296 reset_acpi_log();
297}
298
299
300static u32
301transmit(u8 locty, const struct iovec iovec[],
302 u8 *respbuffer, u32 *respbufferlen,
303 enum tpmDurationType to_t)
304{
305 u32 rc = 0;
306 u32 irc;
307 struct tpm_driver *td;
308 unsigned int i;
309
310 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
311 return TCG_FATAL_COM_ERROR;
312
313 td = &tpm_drivers[tpm_state.tpm_driver_to_use];
314
315 irc = td->activate(locty);
316 if (irc != 0) {
317 /* tpm could not be activated */
318 return TCG_FATAL_COM_ERROR;
319 }
320
321 for (i = 0; iovec[i].length; i++) {
322 irc = td->senddata(iovec[i].data,
323 iovec[i].length);
324 if (irc != 0)
325 return TCG_FATAL_COM_ERROR;
326 }
327
328 irc = td->waitdatavalid();
329 if (irc != 0)
330 return TCG_FATAL_COM_ERROR;
331
332 irc = td->waitrespready(to_t);
333 if (irc != 0)
334 return TCG_FATAL_COM_ERROR;
335
336 irc = td->readresp(respbuffer,
337 respbufferlen);
338 if (irc != 0)
339 return TCG_FATAL_COM_ERROR;
340
341 td->ready();
342
343 return rc;
344}
345
346
347/*
348 * Send a TPM command with the given ordinal. Append the given buffer
349 * containing all data in network byte order to the command (this is
350 * the custom part per command) and expect a response of the given size.
351 * If a buffer is provided, the response will be copied into it.
352 */
353static u32
Stefan Berger47b9df52015-11-21 14:54:40 -0500354build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
355 u8 *resbuffer, u32 return_size, u32 *returnCode,
356 enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400357{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400358 u32 rc;
Stefan Bergerece25612015-11-12 10:14:46 -0500359 u8 obuffer[64];
360 struct tpm_req_header trqh;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400361 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Berger47b9df52015-11-21 14:54:40 -0500362 struct iovec iovec[3] = {{ 0 }};
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400363 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400364
Stefan Bergerece25612015-11-12 10:14:46 -0500365 if (return_size > sizeof(obuffer)) {
366 dprintf(DEBUG_tcg, "TCGBIOS: size of requested response too big.");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400367 return TCG_FIRMWARE_ERROR;
368 }
369
Stefan Bergerece25612015-11-12 10:14:46 -0500370 trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
Stefan Berger47b9df52015-11-21 14:54:40 -0500371 trqh.totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size);
Stefan Bergerece25612015-11-12 10:14:46 -0500372 trqh.ordinal = cpu_to_be32(ordinal);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400373
Stefan Bergerece25612015-11-12 10:14:46 -0500374 iovec[0].data = &trqh;
375 iovec[0].length = TPM_REQ_HEADER_SIZE;
376
377 if (append_size) {
378 iovec[1].data = append;
379 iovec[1].length = append_size;
Stefan Bergerece25612015-11-12 10:14:46 -0500380 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400381
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400382 memset(obuffer, 0x0, sizeof(obuffer));
383
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400384 rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
385 if (rc)
386 return rc;
387
388 *returnCode = be32_to_cpu(trsh->errcode);
389
390 if (resbuffer)
391 memcpy(resbuffer, trsh, return_size);
392
393 return 0;
394}
395
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400396static u32
397determine_timeouts(void)
398{
399 u32 rc;
400 u32 returnCode;
401 struct tpm_res_getcap_timeouts timeouts;
402 struct tpm_res_getcap_durations durations;
403 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
404 u32 i;
405
Stefan Berger5aa2a752015-03-23 14:22:17 -0400406 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400407 GetCapability_Timeouts,
408 sizeof(GetCapability_Timeouts),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400409 (u8 *)&timeouts, sizeof(timeouts),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400410 &returnCode, TPM_DURATION_TYPE_SHORT);
411
412 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
413 " = 0x%08x\n", returnCode);
414
415 if (rc || returnCode)
416 goto err_exit;
417
Stefan Berger5aa2a752015-03-23 14:22:17 -0400418 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400419 GetCapability_Durations,
420 sizeof(GetCapability_Durations),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400421 (u8 *)&durations, sizeof(durations),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400422 &returnCode, TPM_DURATION_TYPE_SHORT);
423
424 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
425 " = 0x%08x\n", returnCode);
426
427 if (rc || returnCode)
428 goto err_exit;
429
430 for (i = 0; i < 3; i++)
431 durations.durations[i] = be32_to_cpu(durations.durations[i]);
432
433 for (i = 0; i < 4; i++)
434 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
435
436 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
437 timeouts.timeouts[0],
438 timeouts.timeouts[1],
439 timeouts.timeouts[2],
440 timeouts.timeouts[3]);
441
442 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
443 durations.durations[0],
444 durations.durations[1],
445 durations.durations[2]);
446
447
448 td->set_timeouts(timeouts.timeouts, durations.durations);
449
450 return 0;
451
452err_exit:
453 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
454
Stefan Berger7fce1d92015-11-12 10:14:45 -0500455 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400456 if (rc)
457 return rc;
458 return TCG_TCG_COMMAND_ERROR;
459}
460
461
462static u32
463tpm_startup(void)
464{
465 u32 rc;
466 u32 returnCode;
467
468 if (!has_working_tpm())
469 return TCG_GENERAL_ERROR;
470
471 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400472 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400473 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400474 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400475
476 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
477 returnCode);
478
479 if (CONFIG_COREBOOT) {
480 /* with other firmware on the system the TPM may already have been
481 * initialized
482 */
483 if (returnCode == TPM_INVALID_POSTINIT)
484 returnCode = 0;
485 }
486
487 if (rc || returnCode)
488 goto err_exit;
489
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500490 rc = determine_timeouts();
491 if (rc)
492 goto err_exit;
493
Stefan Berger5aa2a752015-03-23 14:22:17 -0400494 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400495 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400496
497 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
498 returnCode);
499
500 if (rc || returnCode)
501 goto err_exit;
502
Stefan Berger5aa2a752015-03-23 14:22:17 -0400503 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400504 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400505
506 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
507 returnCode);
508
509 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
510 goto err_exit;
511
Stefan Berger2aff1c12015-05-26 15:48:33 -0400512 rc = tpm_smbios_measure();
513 if (rc)
514 goto err_exit;
515
516 rc = tpm_start_option_rom_scan();
517 if (rc)
518 goto err_exit;
519
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400520 return 0;
521
522err_exit:
523 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
524
Stefan Berger7fce1d92015-11-12 10:14:45 -0500525 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400526 if (rc)
527 return rc;
528 return TCG_TCG_COMMAND_ERROR;
529}
530
531
Kevin O'Connord6aca442015-06-10 11:00:17 -0400532void
533tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400534{
535 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400536 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400537
538 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400539 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400540 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400541
Kevin O'Connord6aca442015-06-10 11:00:17 -0400542 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400543}
544
545
Kevin O'Connord6aca442015-06-10 11:00:17 -0400546void
547tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400548{
549 u32 rc;
550 u32 returnCode;
551
552 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400553 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400554
555 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400556 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400557
Stefan Berger5aa2a752015-03-23 14:22:17 -0400558 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400559 PhysicalPresence_CMD_ENABLE,
560 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400561 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400562 if (rc || returnCode)
563 goto err_exit;
564
Stefan Berger5aa2a752015-03-23 14:22:17 -0400565 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400566 PhysicalPresence_NOT_PRESENT_LOCK,
567 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400568 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400569 if (rc || returnCode)
570 goto err_exit;
571
Stefan Berger2aff1c12015-05-26 15:48:33 -0400572 rc = tpm_calling_int19h();
573 if (rc)
574 goto err_exit;
575
576 rc = tpm_add_event_separators();
577 if (rc)
578 goto err_exit;
579
Kevin O'Connord6aca442015-06-10 11:00:17 -0400580 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400581
582err_exit:
583 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
584
Stefan Berger7fce1d92015-11-12 10:14:45 -0500585 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400586}
587
Stefan Berger5aa2a752015-03-23 14:22:17 -0400588/*
589 * Extend the ACPI log with the given entry by copying the
590 * entry data into the log.
591 * Input
Stefan Bergere3cc6322015-11-12 10:14:47 -0500592 * pcpes : Pointer to the event 'header' to be copied into the log
593 * event : Pointer to the event 'body' to be copied into the log
594 * event_length: Length of the event array
595 * entry_count : optional pointer to get the current entry count
Stefan Berger5aa2a752015-03-23 14:22:17 -0400596 *
597 * Output:
Stefan Bergere3cc6322015-11-12 10:14:47 -0500598 * Returns an error code in case of faiure, 0 in case of success
Stefan Berger5aa2a752015-03-23 14:22:17 -0400599 */
600static u32
Stefan Bergere3cc6322015-11-12 10:14:47 -0500601tpm_extend_acpi_log(struct pcpes *pcpes,
602 const char *event, u32 event_length,
603 u16 *entry_count)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400604{
Stefan Berger60bb9e92015-11-21 14:54:42 -0500605 u32 size;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400606
Stefan Berger7fce1d92015-11-12 10:14:45 -0500607 if (!has_working_tpm())
608 return TCG_GENERAL_ERROR;
609
Stefan Berger60bb9e92015-11-21 14:54:42 -0500610 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
611 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
Stefan Berger5aa2a752015-03-23 14:22:17 -0400612
Stefan Berger60bb9e92015-11-21 14:54:42 -0500613 if (tpm_state.log_area_next_entry == NULL) {
Stefan Berger5aa2a752015-03-23 14:22:17 -0400614
Stefan Berger7fce1d92015-11-12 10:14:45 -0500615 tpm_set_failure();
616
Stefan Berger5aa2a752015-03-23 14:22:17 -0400617 return TCG_PC_LOGOVERFLOW;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500618 }
Stefan Berger5aa2a752015-03-23 14:22:17 -0400619
Stefan Bergere3cc6322015-11-12 10:14:47 -0500620 size = offsetof(struct pcpes, event) + event_length;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400621
Stefan Berger60bb9e92015-11-21 14:54:42 -0500622 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
623 tpm_state.log_area_minimum_length) {
Stefan Berger5aa2a752015-03-23 14:22:17 -0400624 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Stefan Berger7fce1d92015-11-12 10:14:45 -0500625
626 tpm_set_failure();
627
Stefan Berger5aa2a752015-03-23 14:22:17 -0400628 return TCG_PC_LOGOVERFLOW;
629 }
630
Stefan Bergere3cc6322015-11-12 10:14:47 -0500631 pcpes->eventdatasize = event_length;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400632
Stefan Berger60bb9e92015-11-21 14:54:42 -0500633 memcpy(tpm_state.log_area_next_entry, pcpes, offsetof(struct pcpes, event));
634 memcpy(tpm_state.log_area_next_entry + offsetof(struct pcpes, event),
Stefan Bergere3cc6322015-11-12 10:14:47 -0500635 event, event_length);
636
Stefan Berger60bb9e92015-11-21 14:54:42 -0500637 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
638 tpm_state.log_area_next_entry += size;
639 tpm_state.entry_count++;
640
Stefan Bergere3cc6322015-11-12 10:14:47 -0500641 if (entry_count)
Stefan Berger60bb9e92015-11-21 14:54:42 -0500642 *entry_count = tpm_state.entry_count;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400643
644 return 0;
645}
646
647
648static u32
649is_preboot_if_shutdown(void)
650{
651 return tpm_state.if_shutdown;
652}
653
654
655static u32
656shutdown_preboot_interface(void)
657{
658 u32 rc = 0;
659
660 if (!is_preboot_if_shutdown()) {
661 tpm_state.if_shutdown = 1;
662 } else {
663 rc = TCG_INTERFACE_SHUTDOWN;
664 }
665
666 return rc;
667}
668
669
670static void
671tpm_shutdown(void)
672{
673 reset_acpi_log();
674 shutdown_preboot_interface();
675}
676
677
678static u32
679pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
680{
681 u32 rc = 0;
682 u32 resbuflen = 0;
683 struct tpm_req_header *trh;
684 u8 locty = 0;
685 struct iovec iovec[2];
686 const u32 *tmp;
687
688 if (is_preboot_if_shutdown()) {
689 rc = TCG_INTERFACE_SHUTDOWN;
690 goto err_exit;
691 }
692
693 trh = (struct tpm_req_header *)pttti->tpmopin;
694
695 if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
696 pttti->opblength < sizeof(struct pttto) ||
697 be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) {
698 rc = TCG_INVALID_INPUT_PARA;
699 goto err_exit;
700 }
701
702 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
703
704 iovec[0].data = pttti->tpmopin;
705 tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
706 iovec[0].length = cpu_to_be32(*tmp);
707
708 iovec[1].data = NULL;
709 iovec[1].length = 0;
710
711 rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen,
712 TPM_DURATION_TYPE_LONG /* worst case */);
713 if (rc)
714 goto err_exit;
715
716 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
717 pttto->reserved = 0;
718
719err_exit:
720 if (rc != 0) {
721 pttto->opblength = 4;
722 pttto->reserved = 0;
723 }
724
725 return rc;
726}
727
728
729static u32
730tpm_extend(u8 *hash, u32 pcrindex)
731{
732 u32 rc;
733 struct pttto_extend pttto;
734 struct pttti_extend pttti = {
735 .pttti = {
736 .ipblength = sizeof(struct pttti_extend),
737 .opblength = sizeof(struct pttto_extend),
738 },
739 .req = {
740 .tag = cpu_to_be16(0xc1),
741 .totlen = cpu_to_be32(sizeof(pttti.req)),
742 .ordinal = cpu_to_be32(TPM_ORD_Extend),
743 .pcrindex = cpu_to_be32(pcrindex),
744 },
745 };
746
747 memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
748
749 rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
750
751 if (rc == 0) {
752 if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE ||
753 pttto.pttto.opblength !=
754 sizeof(struct pttto) + be32_to_cpu(pttto.rsp.totlen) ||
755 be16_to_cpu(pttto.rsp.tag) != 0xc4) {
756 rc = TCG_FATAL_COM_ERROR;
757 }
758 }
759
760 if (rc)
761 tpm_shutdown();
762
763 return rc;
764}
765
766
767static u32
768hash_all(const struct hai *hai, u8 *hash)
769{
770 if (is_preboot_if_shutdown() != 0)
771 return TCG_INTERFACE_SHUTDOWN;
772
773 if (hai->ipblength != sizeof(struct hai) ||
774 hai->hashdataptr == 0 ||
775 hai->hashdatalen == 0 ||
776 hai->algorithmid != TPM_ALG_SHA)
777 return TCG_INVALID_INPUT_PARA;
778
Stefan Berger47b9df52015-11-21 14:54:40 -0500779 return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
Stefan Berger5aa2a752015-03-23 14:22:17 -0400780}
781
Stefan Berger129c04b2015-11-12 10:14:48 -0500782static u32
783hash_log_event(const void *hashdata, u32 hashdata_length,
784 struct pcpes *pcpes,
785 const char *event, u32 event_length,
786 u16 *entry_count)
787{
788 u32 rc = 0;
789
790 if (pcpes->pcrindex >= 24)
791 return TCG_INVALID_INPUT_PARA;
792
793 if (hashdata) {
Stefan Berger47b9df52015-11-21 14:54:40 -0500794 rc = sha1(hashdata, hashdata_length, pcpes->digest);
Stefan Berger129c04b2015-11-12 10:14:48 -0500795 if (rc)
796 return rc;
797 }
798
799 return tpm_extend_acpi_log(pcpes, event, event_length, entry_count);
800}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400801
802static u32
Stefan Berger129c04b2015-11-12 10:14:48 -0500803hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400804{
805 u32 rc = 0;
806 u16 size;
807 struct pcpes *pcpes;
808 u16 entry_count;
809
810 if (is_preboot_if_shutdown() != 0) {
811 rc = TCG_INTERFACE_SHUTDOWN;
812 goto err_exit;
813 }
814
815 size = hlei->ipblength;
816 if (size != sizeof(*hlei)) {
817 rc = TCG_INVALID_INPUT_PARA;
818 goto err_exit;
819 }
820
821 pcpes = (struct pcpes *)hlei->logdataptr;
822
823 if (pcpes->pcrindex >= 24 ||
824 pcpes->pcrindex != hlei->pcrindex ||
Stefan Berger129c04b2015-11-12 10:14:48 -0500825 pcpes->eventtype != hlei->logeventtype ||
826 hlei->logdatalen !=
827 offsetof(struct pcpes, event) + pcpes->eventdatasize) {
Stefan Berger5aa2a752015-03-23 14:22:17 -0400828 rc = TCG_INVALID_INPUT_PARA;
829 goto err_exit;
830 }
831
Stefan Berger129c04b2015-11-12 10:14:48 -0500832 rc = hash_log_event(hlei->hashdataptr, hlei->hashdatalen,
833 pcpes, (char *)&pcpes->event, pcpes->eventdatasize,
834 &entry_count);
Stefan Berger5aa2a752015-03-23 14:22:17 -0400835 if (rc)
836 goto err_exit;
837
838 /* updating the log was fine */
839 hleo->opblength = sizeof(struct hleo);
840 hleo->reserved = 0;
841 hleo->eventnumber = entry_count;
842
843err_exit:
844 if (rc != 0) {
845 hleo->opblength = 2;
846 hleo->reserved = 0;
847 }
848
849 return rc;
850}
851
Stefan Berger6c376b42015-11-12 10:14:49 -0500852static u32
853hash_log_extend_event(const void *hashdata, u32 hashdata_length,
854 struct pcpes *pcpes,
855 const char *event, u32 event_length,
856 u32 pcrindex, u16 *entry_count)
857{
858 u32 rc;
859
860 rc = hash_log_event(hashdata, hashdata_length, pcpes,
861 event, event_length, entry_count);
862 if (rc)
863 return rc;
864
865 return tpm_extend(pcpes->digest, pcrindex);
866}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400867
868static u32
Stefan Berger6c376b42015-11-12 10:14:49 -0500869hash_log_extend_event_int(const struct hleei_short *hleei_s,
870 struct hleeo *hleeo)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400871{
872 u32 rc = 0;
873 struct hleo hleo;
874 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
875 const void *logdataptr;
876 u32 logdatalen;
877 struct pcpes *pcpes;
Stefan Berger6c376b42015-11-12 10:14:49 -0500878 u32 pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400879
880 /* short or long version? */
881 switch (hleei_s->ipblength) {
882 case sizeof(struct hleei_short):
883 /* short */
884 logdataptr = hleei_s->logdataptr;
885 logdatalen = hleei_s->logdatalen;
Stefan Berger6c376b42015-11-12 10:14:49 -0500886 pcrindex = hleei_s->pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400887 break;
888
889 case sizeof(struct hleei_long):
890 /* long */
891 logdataptr = hleei_l->logdataptr;
892 logdatalen = hleei_l->logdatalen;
Stefan Berger6c376b42015-11-12 10:14:49 -0500893 pcrindex = hleei_l->pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400894 break;
895
896 default:
897 /* bad input block */
898 rc = TCG_INVALID_INPUT_PARA;
899 goto err_exit;
900 }
901
902 pcpes = (struct pcpes *)logdataptr;
903
Stefan Berger6c376b42015-11-12 10:14:49 -0500904 if (pcpes->pcrindex >= 24 ||
905 pcpes->pcrindex != pcrindex ||
906 logdatalen != offsetof(struct pcpes, event) + pcpes->eventdatasize) {
907 rc = TCG_INVALID_INPUT_PARA;
908 goto err_exit;
909 }
910
911 rc = hash_log_extend_event(hleei_s->hashdataptr, hleei_s->hashdatalen,
912 pcpes,
913 (char *)&pcpes->event, pcpes->eventdatasize,
914 pcrindex, NULL);
Stefan Berger5aa2a752015-03-23 14:22:17 -0400915 if (rc)
916 goto err_exit;
917
918 hleeo->opblength = sizeof(struct hleeo);
919 hleeo->reserved = 0;
920 hleeo->eventnumber = hleo.eventnumber;
921
Stefan Berger5aa2a752015-03-23 14:22:17 -0400922err_exit:
923 if (rc != 0) {
924 hleeo->opblength = 4;
925 hleeo->reserved = 0;
926 }
927
928 return rc;
929
930}
931
932
933static u32
934tss(struct ti *ti, struct to *to)
935{
936 u32 rc = 0;
937
938 if (is_preboot_if_shutdown() == 0) {
939 rc = TCG_PC_UNSUPPORTED;
940 } else {
941 rc = TCG_INTERFACE_SHUTDOWN;
942 }
943
944 to->opblength = sizeof(struct to);
945 to->reserved = 0;
946
947 return rc;
948}
949
950
951static u32
952compact_hash_log_extend_event(u8 *buffer,
953 u32 info,
954 u32 length,
955 u32 pcrindex,
956 u32 *edx_ptr)
957{
958 u32 rc = 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400959 struct pcpes pcpes = {
960 .pcrindex = pcrindex,
961 .eventtype = EV_COMPACT_HASH,
962 .eventdatasize = sizeof(info),
963 .event = info,
964 };
Stefan Berger6c376b42015-11-12 10:14:49 -0500965 u16 entry_count;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400966
Stefan Berger6c376b42015-11-12 10:14:49 -0500967 rc = hash_log_extend_event(buffer, length,
968 &pcpes,
969 (char *)&pcpes.event, pcpes.eventdatasize,
970 pcpes.pcrindex, &entry_count);
971
Stefan Berger5aa2a752015-03-23 14:22:17 -0400972 if (rc == 0)
Stefan Berger6c376b42015-11-12 10:14:49 -0500973 *edx_ptr = entry_count;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400974
975 return rc;
976}
977
978
979void VISIBLE32FLAT
980tpm_interrupt_handler32(struct bregs *regs)
981{
982 if (!CONFIG_TCGBIOS)
983 return;
984
985 set_cf(regs, 0);
986
987 if (!has_working_tpm()) {
988 regs->eax = TCG_GENERAL_ERROR;
989 return;
990 }
991
992 switch ((enum irq_ids)regs->al) {
993 case TCG_StatusCheck:
994 if (is_tpm_present() == 0) {
995 /* no TPM available */
996 regs->eax = TCG_PC_TPM_NOT_PRESENT;
997 } else {
998 regs->eax = 0;
999 regs->ebx = TCG_MAGIC;
1000 regs->ch = TCG_VERSION_MAJOR;
1001 regs->cl = TCG_VERSION_MINOR;
1002 regs->edx = 0x0;
Stefan Berger60bb9e92015-11-21 14:54:42 -05001003 regs->esi = (u32)tpm_state.log_area_start_address;
1004 regs->edi = (u32)tpm_state.log_area_last_entry;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001005 }
1006 break;
1007
1008 case TCG_HashLogExtendEvent:
1009 regs->eax =
Stefan Berger6c376b42015-11-12 10:14:49 -05001010 hash_log_extend_event_int(
Stefan Berger5aa2a752015-03-23 14:22:17 -04001011 (struct hleei_short *)input_buf32(regs),
1012 (struct hleeo *)output_buf32(regs));
1013 break;
1014
1015 case TCG_PassThroughToTPM:
1016 regs->eax =
1017 pass_through_to_tpm((struct pttti *)input_buf32(regs),
1018 (struct pttto *)output_buf32(regs));
1019 break;
1020
1021 case TCG_ShutdownPreBootInterface:
1022 regs->eax = shutdown_preboot_interface();
1023 break;
1024
1025 case TCG_HashLogEvent:
Stefan Berger129c04b2015-11-12 10:14:48 -05001026 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1027 (struct hleo*)output_buf32(regs));
Stefan Berger5aa2a752015-03-23 14:22:17 -04001028 break;
1029
1030 case TCG_HashAll:
1031 regs->eax =
1032 hash_all((struct hai*)input_buf32(regs),
1033 (u8 *)output_buf32(regs));
1034 break;
1035
1036 case TCG_TSS:
1037 regs->eax = tss((struct ti*)input_buf32(regs),
1038 (struct to*)output_buf32(regs));
1039 break;
1040
1041 case TCG_CompactHashLogExtendEvent:
1042 regs->eax =
1043 compact_hash_log_extend_event((u8 *)input_buf32(regs),
1044 regs->esi,
1045 regs->ecx,
1046 regs->edx,
1047 &regs->edx);
1048 break;
1049
1050 default:
1051 set_cf(regs, 1);
1052 }
1053
1054 return;
1055}
1056
Stefan Berger2aff1c12015-05-26 15:48:33 -04001057/*
1058 * Add a measurement to the log; the data at data_seg:data/length are
1059 * appended to the TCG_PCClientPCREventStruct
1060 *
1061 * Input parameters:
Stefan Berger6c376b42015-11-12 10:14:49 -05001062 * pcrindex : which PCR to extend
Stefan Berger2aff1c12015-05-26 15:48:33 -04001063 * event_type : type of event; specs section on 'Event Types'
Stefan Berger6c376b42015-11-12 10:14:49 -05001064 * event : pointer to info (e.g., string) to be added to log as-is
1065 * event_length: length of the event
1066 * hashdata : pointer to the data to be hashed
1067 * hashdata_length: length of the data to be hashed
Stefan Berger2aff1c12015-05-26 15:48:33 -04001068 */
1069static u32
Stefan Berger6c376b42015-11-12 10:14:49 -05001070tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
1071 const char *event, u32 event_length,
1072 const u8 *hashdata, u32 hashdata_length)
Stefan Berger2aff1c12015-05-26 15:48:33 -04001073{
Stefan Berger6c376b42015-11-12 10:14:49 -05001074 struct pcpes pcpes = {
1075 .pcrindex = pcrindex,
1076 .eventtype = event_type,
1077 };
1078 u16 entry_count;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001079
Stefan Berger6c376b42015-11-12 10:14:49 -05001080 return hash_log_extend_event(hashdata, hashdata_length, &pcpes,
1081 event, event_length, pcrindex,
1082 &entry_count);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001083}
1084
1085
1086/*
1087 * Add a measurement to the list of measurements
1088 * pcrIndex : PCR to be extended
1089 * event_type : type of event; specs section on 'Event Types'
1090 * data : additional parameter; used as parameter for
1091 * 'action index'
1092 */
1093static u32
1094tpm_add_measurement(u32 pcrIndex,
1095 u16 event_type,
1096 const char *string)
1097{
1098 u32 rc;
1099 u32 len;
1100
1101 switch (event_type) {
1102 case EV_SEPARATOR:
1103 len = sizeof(evt_separator);
1104 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1105 (char *)NULL, 0,
1106 (u8 *)evt_separator, len);
1107 break;
1108
1109 case EV_ACTION:
1110 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1111 string, strlen(string),
1112 (u8 *)string, strlen(string));
1113 break;
1114
1115 default:
1116 rc = TCG_INVALID_INPUT_PARA;
1117 }
1118
1119 return rc;
1120}
1121
1122
1123static u32
1124tpm_calling_int19h(void)
1125{
1126 if (!CONFIG_TCGBIOS)
1127 return 0;
1128
1129 if (!has_working_tpm())
1130 return TCG_GENERAL_ERROR;
1131
1132 return tpm_add_measurement(4, EV_ACTION,
1133 "Calling INT 19h");
1134}
1135
1136/*
1137 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
1138 */
1139u32
1140tpm_add_event_separators(void)
1141{
1142 u32 rc;
1143 u32 pcrIndex = 0;
1144
1145 if (!CONFIG_TCGBIOS)
1146 return 0;
1147
1148 if (!has_working_tpm())
1149 return TCG_GENERAL_ERROR;
1150
1151 while (pcrIndex <= 7) {
1152 rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
1153 if (rc)
1154 break;
1155 pcrIndex ++;
1156 }
1157
1158 return rc;
1159}
1160
1161
1162/*
1163 * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
1164 * the list of measurements.
1165 */
1166static u32
1167tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
1168{
1169 const char *string;
1170
1171 if (!CONFIG_TCGBIOS)
1172 return 0;
1173
1174 if (!has_working_tpm())
1175 return TCG_GENERAL_ERROR;
1176
1177 switch (bootcd) {
1178 case 0:
1179 switch (bootdrv) {
1180 case 0:
1181 string = "Booting BCV device 00h (Floppy)";
1182 break;
1183
1184 case 0x80:
1185 string = "Booting BCV device 80h (HDD)";
1186 break;
1187
1188 default:
1189 string = "Booting unknown device";
1190 break;
1191 }
1192
1193 break;
1194
1195 default:
1196 string = "Booting from CD ROM device";
1197 }
1198
1199 return tpm_add_measurement_to_log(4, EV_ACTION,
1200 string, strlen(string),
1201 (u8 *)string, strlen(string));
1202}
1203
1204
1205/*
1206 * Add measurement to the log about option rom scan
1207 */
1208u32
1209tpm_start_option_rom_scan(void)
1210{
1211 if (!CONFIG_TCGBIOS)
1212 return 0;
1213
1214 if (!has_working_tpm())
1215 return TCG_GENERAL_ERROR;
1216
1217 return tpm_add_measurement(2, EV_ACTION,
1218 "Start Option ROM Scan");
1219}
1220
1221
1222/*
1223 * Add measurement to the log about an option rom
1224 */
1225u32
1226tpm_option_rom(const void *addr, u32 len)
1227{
1228 if (!CONFIG_TCGBIOS)
1229 return 0;
1230
1231 if (!has_working_tpm())
1232 return TCG_GENERAL_ERROR;
1233
1234 u32 rc;
1235 struct pcctes_romex pcctes = {
1236 .eventid = 7,
1237 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
1238 };
1239
1240 rc = sha1((const u8 *)addr, len, pcctes.digest);
1241 if (rc)
1242 return rc;
1243
1244 return tpm_add_measurement_to_log(2,
1245 EV_EVENT_TAG,
1246 (const char *)&pcctes, sizeof(pcctes),
1247 (u8 *)&pcctes, sizeof(pcctes));
1248}
1249
1250
1251u32
1252tpm_smbios_measure(void)
1253{
1254 if (!CONFIG_TCGBIOS)
1255 return 0;
1256
1257 if (!has_working_tpm())
1258 return TCG_GENERAL_ERROR;
1259
1260 u32 rc;
1261 struct pcctes pcctes = {
1262 .eventid = 1,
1263 .eventdatasize = SHA1_BUFSIZE,
1264 };
1265 struct smbios_entry_point *sep = SMBiosAddr;
1266
1267 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
1268
1269 if (!sep)
1270 return 0;
1271
1272 rc = sha1((const u8 *)sep->structure_table_address,
1273 sep->structure_table_length, pcctes.digest);
1274 if (rc)
1275 return rc;
1276
1277 return tpm_add_measurement_to_log(1,
1278 EV_EVENT_TAG,
1279 (const char *)&pcctes, sizeof(pcctes),
1280 (u8 *)&pcctes, sizeof(pcctes));
1281}
1282
1283
1284/*
1285 * Add a measurement related to Initial Program Loader to the log.
1286 * Creates two log entries.
1287 *
1288 * Input parameter:
1289 * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
1290 * addr : address where the IP data are located
1291 * length : IP data length in bytes
1292 */
1293static u32
1294tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
1295{
1296 u32 rc;
1297 const char *string;
1298
1299 switch (bootcd) {
1300 case IPL_EL_TORITO_1:
1301 /* specs: see section 'El Torito' */
1302 string = "EL TORITO IPL";
1303 rc = tpm_add_measurement_to_log(4, EV_IPL,
1304 string, strlen(string),
1305 addr, length);
1306 break;
1307
1308 case IPL_EL_TORITO_2:
1309 /* specs: see section 'El Torito' */
1310 string = "BOOT CATALOG";
1311 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1312 string, strlen(string),
1313 addr, length);
1314 break;
1315
1316 default:
1317 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1318 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
1319 string = "MBR";
1320 rc = tpm_add_measurement_to_log(4, EV_IPL,
1321 string, strlen(string),
1322 addr, 0x1b8);
1323
1324 if (rc)
1325 break;
1326
1327 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
1328 string = "MBR PARTITION_TABLE";
1329 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1330 string, strlen(string),
1331 addr + 0x1b8, 0x48);
1332 }
1333
1334 return rc;
1335}
1336
1337u32
1338tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1339{
1340 if (!CONFIG_TCGBIOS)
1341 return 0;
1342
1343 if (!has_working_tpm())
1344 return TCG_GENERAL_ERROR;
1345
1346 u32 rc = tpm_add_bootdevice(0, bootdrv);
1347 if (rc)
1348 return rc;
1349
1350 return tpm_ipl(IPL_BCV, addr, length);
1351}
1352
1353u32
1354tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1355{
1356 if (!CONFIG_TCGBIOS)
1357 return 0;
1358
1359 if (!has_working_tpm())
1360 return TCG_GENERAL_ERROR;
1361
1362 u32 rc = tpm_add_bootdevice(1, bootdrv);
1363 if (rc)
1364 return rc;
1365
1366 return tpm_ipl(IPL_EL_TORITO_1, addr, length);
1367}
1368
1369u32
1370tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1371{
1372 if (!CONFIG_TCGBIOS)
1373 return 0;
1374
1375 if (!has_working_tpm())
1376 return TCG_GENERAL_ERROR;
1377
1378 u32 rc = tpm_add_bootdevice(1, 0);
1379 if (rc)
1380 return rc;
1381
1382 return tpm_ipl(IPL_EL_TORITO_2, addr, length);
1383}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001384
Kevin O'Connord6aca442015-06-10 11:00:17 -04001385void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001386tpm_s3_resume(void)
1387{
1388 u32 rc;
1389 u32 returnCode;
1390
1391 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001392 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001393
1394 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001395 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001396
1397 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1398
Stefan Berger5aa2a752015-03-23 14:22:17 -04001399 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001400 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -04001401 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001402
1403 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
1404 returnCode);
1405
1406 if (rc || returnCode)
1407 goto err_exit;
1408
Kevin O'Connord6aca442015-06-10 11:00:17 -04001409 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001410
1411err_exit:
1412 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1413
Stefan Berger7fce1d92015-11-12 10:14:45 -05001414 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001415}