blob: 9ae075a4cabec0bc115a24a330bfd2517df9b4b5 [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;
93} tpm_state_t;
94
95
96static tpm_state_t tpm_state = {
97 .tpm_driver_to_use = TPM_INVALID_DRIVER,
98};
99
100
101/********************************************************
102 Extensions for TCG-enabled BIOS
103 *******************************************************/
104
105
106static u32
107is_tpm_present(void)
108{
109 u32 rc = 0;
110 unsigned int i;
111
112 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
113 struct tpm_driver *td = &tpm_drivers[i];
114 if (td->probe() != 0) {
115 td->init();
116 tpm_state.tpm_driver_to_use = i;
117 rc = 1;
118 break;
119 }
120 }
121
122 return rc;
123}
124
125static void
126probe_tpm(void)
127{
128 if (!tpm_state.tpm_probed) {
129 tpm_state.tpm_probed = 1;
130 tpm_state.tpm_found = (is_tpm_present() != 0);
131 tpm_state.tpm_working = tpm_state.tpm_found;
132 }
133}
134
135static int
136has_working_tpm(void)
137{
138 probe_tpm();
139
140 return tpm_state.tpm_working;
141}
142
Stefan Berger7fce1d92015-11-12 10:14:45 -0500143static void
144tpm_set_failure(void)
145{
146 u32 returnCode;
147
148 /* we will try to deactivate the TPM now - ignoring all errors */
149 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
150 PhysicalPresence_CMD_ENABLE,
151 sizeof(PhysicalPresence_CMD_ENABLE),
152 NULL, 0, &returnCode,
153 TPM_DURATION_TYPE_SHORT);
154
155 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
156 PhysicalPresence_PRESENT,
157 sizeof(PhysicalPresence_PRESENT),
158 NULL, 0, &returnCode,
159 TPM_DURATION_TYPE_SHORT);
160
161 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
162 NULL, 0, NULL, 0, &returnCode,
163 TPM_DURATION_TYPE_SHORT);
164
165 tpm_state.tpm_working = 0;
166}
167
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400168static struct tcpa_descriptor_rev2 *
169find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
170{
171 u32 ctr = 0;
172 struct tcpa_descriptor_rev2 *tcpa = NULL;
173 struct rsdt_descriptor *rsdt;
174 u32 length;
175 u16 off;
176
177 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
178 if (!rsdt)
179 return NULL;
180
181 length = rsdt->length;
182 off = offsetof(struct rsdt_descriptor, entry);
183
184 while ((off + sizeof(rsdt->entry[0])) <= length) {
185 /* try all pointers to structures */
186 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
187
188 /* valid TCPA ACPI table ? */
189 if (tcpa->signature == TCPA_SIGNATURE &&
190 checksum((u8 *)tcpa, tcpa->length) == 0)
191 break;
192
193 tcpa = NULL;
194 off += sizeof(rsdt->entry[0]);
195 ctr++;
196 }
197
198 return tcpa;
199}
200
201
202static struct tcpa_descriptor_rev2 *
203find_tcpa_table(void)
204{
205 struct tcpa_descriptor_rev2 *tcpa = NULL;
206 struct rsdp_descriptor *rsdp = RsdpAddr;
207
208 if (rsdp)
209 tcpa = find_tcpa_by_rsdp(rsdp);
210 else
211 tpm_state.if_shutdown = 1;
212
213 if (!rsdp)
214 dprintf(DEBUG_tcg,
215 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
216 else if (!tcpa)
217 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
218
219 return tcpa;
220}
221
222
223static u8 *
224get_lasa_base_ptr(u32 *log_area_minimum_length)
225{
226 u8 *log_area_start_address = 0;
227 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
228
229 if (tcpa) {
230 log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
231 if (log_area_minimum_length)
232 *log_area_minimum_length = tcpa->log_area_minimum_length;
233 }
234
235 return log_area_start_address;
236}
237
238
239/* clear the ACPI log */
240static void
241reset_acpi_log(void)
242{
243 u32 log_area_minimum_length;
244 u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
245
246 if (log_area_start_address)
247 memset(log_area_start_address, 0x0, log_area_minimum_length);
248}
249
250
251/*
252 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
253 where the TCPA table is.
254 */
255static void
256tpm_acpi_init(void)
257{
258 tpm_state.if_shutdown = 0;
259 tpm_state.tpm_probed = 0;
260 tpm_state.tpm_found = 0;
261 tpm_state.tpm_working = 0;
262
263 if (!has_working_tpm()) {
264 tpm_state.if_shutdown = 1;
265 return;
266 }
267
268 reset_acpi_log();
269}
270
271
272static u32
273transmit(u8 locty, const struct iovec iovec[],
274 u8 *respbuffer, u32 *respbufferlen,
275 enum tpmDurationType to_t)
276{
277 u32 rc = 0;
278 u32 irc;
279 struct tpm_driver *td;
280 unsigned int i;
281
282 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
283 return TCG_FATAL_COM_ERROR;
284
285 td = &tpm_drivers[tpm_state.tpm_driver_to_use];
286
287 irc = td->activate(locty);
288 if (irc != 0) {
289 /* tpm could not be activated */
290 return TCG_FATAL_COM_ERROR;
291 }
292
293 for (i = 0; iovec[i].length; i++) {
294 irc = td->senddata(iovec[i].data,
295 iovec[i].length);
296 if (irc != 0)
297 return TCG_FATAL_COM_ERROR;
298 }
299
300 irc = td->waitdatavalid();
301 if (irc != 0)
302 return TCG_FATAL_COM_ERROR;
303
304 irc = td->waitrespready(to_t);
305 if (irc != 0)
306 return TCG_FATAL_COM_ERROR;
307
308 irc = td->readresp(respbuffer,
309 respbufferlen);
310 if (irc != 0)
311 return TCG_FATAL_COM_ERROR;
312
313 td->ready();
314
315 return rc;
316}
317
318
319/*
320 * Send a TPM command with the given ordinal. Append the given buffer
321 * containing all data in network byte order to the command (this is
322 * the custom part per command) and expect a response of the given size.
323 * If a buffer is provided, the response will be copied into it.
324 */
325static u32
Stefan Berger5aa2a752015-03-23 14:22:17 -0400326build_and_send_cmd_od(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400327 u8 *resbuffer, u32 return_size, u32 *returnCode,
328 const u8 *otherdata, u32 otherdata_size,
329 enum tpmDurationType to_t)
330{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400331 u32 rc;
Stefan Bergerece25612015-11-12 10:14:46 -0500332 u8 obuffer[64];
333 struct tpm_req_header trqh;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400334 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerece25612015-11-12 10:14:46 -0500335 struct iovec iovec[4] = {{ 0 }};
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400336 u32 obuffer_len = sizeof(obuffer);
337 u32 idx = 1;
338
Stefan Bergerece25612015-11-12 10:14:46 -0500339 if (return_size > sizeof(obuffer)) {
340 dprintf(DEBUG_tcg, "TCGBIOS: size of requested response too big.");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400341 return TCG_FIRMWARE_ERROR;
342 }
343
Stefan Bergerece25612015-11-12 10:14:46 -0500344 trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
345 trqh.totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size +
346 otherdata_size);
347 trqh.ordinal = cpu_to_be32(ordinal);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400348
Stefan Bergerece25612015-11-12 10:14:46 -0500349 iovec[0].data = &trqh;
350 iovec[0].length = TPM_REQ_HEADER_SIZE;
351
352 if (append_size) {
353 iovec[1].data = append;
354 iovec[1].length = append_size;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400355 idx = 2;
356 }
357
Stefan Bergerece25612015-11-12 10:14:46 -0500358 if (otherdata) {
359 iovec[idx].data = (void *)otherdata;
360 iovec[idx].length = otherdata_size;
361 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400362
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400363 memset(obuffer, 0x0, sizeof(obuffer));
364
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400365 rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
366 if (rc)
367 return rc;
368
369 *returnCode = be32_to_cpu(trsh->errcode);
370
371 if (resbuffer)
372 memcpy(resbuffer, trsh, return_size);
373
374 return 0;
375}
376
377
378static u32
Stefan Berger5aa2a752015-03-23 14:22:17 -0400379build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400380 u8 *resbuffer, u32 return_size, u32 *returnCode,
381 enum tpmDurationType to_t)
382{
Stefan Berger5aa2a752015-03-23 14:22:17 -0400383 return build_and_send_cmd_od(locty, ordinal, append, append_size,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400384 resbuffer, return_size, returnCode,
385 NULL, 0, to_t);
386}
387
388
389static u32
390determine_timeouts(void)
391{
392 u32 rc;
393 u32 returnCode;
394 struct tpm_res_getcap_timeouts timeouts;
395 struct tpm_res_getcap_durations durations;
396 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
397 u32 i;
398
Stefan Berger5aa2a752015-03-23 14:22:17 -0400399 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400400 GetCapability_Timeouts,
401 sizeof(GetCapability_Timeouts),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400402 (u8 *)&timeouts, sizeof(timeouts),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400403 &returnCode, TPM_DURATION_TYPE_SHORT);
404
405 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
406 " = 0x%08x\n", returnCode);
407
408 if (rc || returnCode)
409 goto err_exit;
410
Stefan Berger5aa2a752015-03-23 14:22:17 -0400411 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400412 GetCapability_Durations,
413 sizeof(GetCapability_Durations),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400414 (u8 *)&durations, sizeof(durations),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400415 &returnCode, TPM_DURATION_TYPE_SHORT);
416
417 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
418 " = 0x%08x\n", returnCode);
419
420 if (rc || returnCode)
421 goto err_exit;
422
423 for (i = 0; i < 3; i++)
424 durations.durations[i] = be32_to_cpu(durations.durations[i]);
425
426 for (i = 0; i < 4; i++)
427 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
428
429 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
430 timeouts.timeouts[0],
431 timeouts.timeouts[1],
432 timeouts.timeouts[2],
433 timeouts.timeouts[3]);
434
435 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
436 durations.durations[0],
437 durations.durations[1],
438 durations.durations[2]);
439
440
441 td->set_timeouts(timeouts.timeouts, durations.durations);
442
443 return 0;
444
445err_exit:
446 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
447
Stefan Berger7fce1d92015-11-12 10:14:45 -0500448 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400449 if (rc)
450 return rc;
451 return TCG_TCG_COMMAND_ERROR;
452}
453
454
455static u32
456tpm_startup(void)
457{
458 u32 rc;
459 u32 returnCode;
460
461 if (!has_working_tpm())
462 return TCG_GENERAL_ERROR;
463
464 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400465 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400466 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400467 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400468
469 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
470 returnCode);
471
472 if (CONFIG_COREBOOT) {
473 /* with other firmware on the system the TPM may already have been
474 * initialized
475 */
476 if (returnCode == TPM_INVALID_POSTINIT)
477 returnCode = 0;
478 }
479
480 if (rc || returnCode)
481 goto err_exit;
482
Stefan Berger5aa2a752015-03-23 14:22:17 -0400483 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400484 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400485
486 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
487 returnCode);
488
489 if (rc || returnCode)
490 goto err_exit;
491
Stefan Berger5aa2a752015-03-23 14:22:17 -0400492 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400493 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400494
495 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
496 returnCode);
497
498 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
499 goto err_exit;
500
501 rc = determine_timeouts();
502 if (rc)
503 goto err_exit;
504
Stefan Berger2aff1c12015-05-26 15:48:33 -0400505 rc = tpm_smbios_measure();
506 if (rc)
507 goto err_exit;
508
509 rc = tpm_start_option_rom_scan();
510 if (rc)
511 goto err_exit;
512
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400513 return 0;
514
515err_exit:
516 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
517
Stefan Berger7fce1d92015-11-12 10:14:45 -0500518 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400519 if (rc)
520 return rc;
521 return TCG_TCG_COMMAND_ERROR;
522}
523
524
Kevin O'Connord6aca442015-06-10 11:00:17 -0400525void
526tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400527{
528 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400529 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400530
531 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400532 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400533 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400534
Kevin O'Connord6aca442015-06-10 11:00:17 -0400535 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400536}
537
538
Kevin O'Connord6aca442015-06-10 11:00:17 -0400539void
540tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400541{
542 u32 rc;
543 u32 returnCode;
544
545 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400546 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400547
548 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400549 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400550
Stefan Berger5aa2a752015-03-23 14:22:17 -0400551 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400552 PhysicalPresence_CMD_ENABLE,
553 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400554 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400555 if (rc || returnCode)
556 goto err_exit;
557
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_NOT_PRESENT_LOCK,
560 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
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 Berger2aff1c12015-05-26 15:48:33 -0400565 rc = tpm_calling_int19h();
566 if (rc)
567 goto err_exit;
568
569 rc = tpm_add_event_separators();
570 if (rc)
571 goto err_exit;
572
Kevin O'Connord6aca442015-06-10 11:00:17 -0400573 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400574
575err_exit:
576 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
577
Stefan Berger7fce1d92015-11-12 10:14:45 -0500578 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400579}
580
Stefan Berger5aa2a752015-03-23 14:22:17 -0400581static int
582is_valid_pcpes(struct pcpes *pcpes)
583{
584 return (pcpes->eventtype != 0);
585}
586
587
588static u8 *
589get_lasa_last_ptr(u16 *entry_count, u8 **log_area_start_address_next)
590{
591 struct pcpes *pcpes;
592 u32 log_area_minimum_length = 0;
593 u8 *log_area_start_address_base =
594 get_lasa_base_ptr(&log_area_minimum_length);
595 u8 *log_area_start_address_last = NULL;
596 u8 *end = log_area_start_address_base + log_area_minimum_length;
597 u32 size;
598
599 if (entry_count)
600 *entry_count = 0;
601
602 if (!log_area_start_address_base)
603 return NULL;
604
605 while (log_area_start_address_base < end) {
606 pcpes = (struct pcpes *)log_area_start_address_base;
607 if (!is_valid_pcpes(pcpes))
608 break;
609 if (entry_count)
610 (*entry_count)++;
611 size = pcpes->eventdatasize + offsetof(struct pcpes, event);
612 log_area_start_address_last = log_area_start_address_base;
613 log_area_start_address_base += size;
614 }
615
616 if (log_area_start_address_next)
617 *log_area_start_address_next = log_area_start_address_base;
618
619 return log_area_start_address_last;
620}
621
622
623static u32
624tpm_sha1_calc(const u8 *data, u32 length, u8 *hash)
625{
626 u32 rc;
627 u32 returnCode;
628 struct tpm_res_sha1start start;
629 struct tpm_res_sha1complete complete;
630 u32 blocks = length / 64;
631 u32 rest = length & 0x3f;
632 u32 numbytes, numbytes_no;
633 u32 offset = 0;
634
635 rc = build_and_send_cmd(0, TPM_ORD_SHA1Start,
636 NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400637 (u8 *)&start, sizeof(start),
Stefan Berger5aa2a752015-03-23 14:22:17 -0400638 &returnCode, TPM_DURATION_TYPE_SHORT);
639
640 if (rc || returnCode)
641 goto err_exit;
642
643 while (blocks > 0) {
644
645 numbytes = be32_to_cpu(start.max_num_bytes);
646 if (numbytes > blocks * 64)
647 numbytes = blocks * 64;
648
649 numbytes_no = cpu_to_be32(numbytes);
650
651 rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Update,
652 (u8 *)&numbytes_no, sizeof(numbytes_no),
653 NULL, 0, &returnCode,
654 &data[offset], numbytes,
655 TPM_DURATION_TYPE_SHORT);
656
657 if (rc || returnCode)
658 goto err_exit;
659
660 offset += numbytes;
661 blocks -= (numbytes / 64);
662 }
663
664 numbytes_no = cpu_to_be32(rest);
665
666 rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Complete,
667 (u8 *)&numbytes_no, sizeof(numbytes_no),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400668 (u8 *)&complete, sizeof(complete),
Stefan Berger5aa2a752015-03-23 14:22:17 -0400669 &returnCode,
670 &data[offset], rest, TPM_DURATION_TYPE_SHORT);
671
672 if (rc || returnCode)
673 goto err_exit;
674
675 memcpy(hash, complete.hash, sizeof(complete.hash));
676
677 return 0;
678
679err_exit:
680 dprintf(DEBUG_tcg, "TCGBIOS: TPM SHA1 malfunctioning.\n");
681
Stefan Berger7fce1d92015-11-12 10:14:45 -0500682 tpm_set_failure();
Stefan Berger5aa2a752015-03-23 14:22:17 -0400683 if (rc)
684 return rc;
685 return TCG_TCG_COMMAND_ERROR;
686}
687
688
689static u32
690sha1_calc(const u8 *data, u32 length, u8 *hash)
691{
692 if (length < tpm_drivers[tpm_state.tpm_driver_to_use].sha1threshold)
693 return tpm_sha1_calc(data, length, hash);
694
695 return sha1(data, length, hash);
696}
697
698
699/*
700 * Extend the ACPI log with the given entry by copying the
701 * entry data into the log.
702 * Input
Stefan Bergere3cc6322015-11-12 10:14:47 -0500703 * pcpes : Pointer to the event 'header' to be copied into the log
704 * event : Pointer to the event 'body' to be copied into the log
705 * event_length: Length of the event array
706 * entry_count : optional pointer to get the current entry count
Stefan Berger5aa2a752015-03-23 14:22:17 -0400707 *
708 * Output:
Stefan Bergere3cc6322015-11-12 10:14:47 -0500709 * Returns an error code in case of faiure, 0 in case of success
Stefan Berger5aa2a752015-03-23 14:22:17 -0400710 */
711static u32
Stefan Bergere3cc6322015-11-12 10:14:47 -0500712tpm_extend_acpi_log(struct pcpes *pcpes,
713 const char *event, u32 event_length,
714 u16 *entry_count)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400715{
716 u32 log_area_minimum_length, size;
717 u8 *log_area_start_address_base =
718 get_lasa_base_ptr(&log_area_minimum_length);
719 u8 *log_area_start_address_next = NULL;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400720
Stefan Berger7fce1d92015-11-12 10:14:45 -0500721 if (!has_working_tpm())
722 return TCG_GENERAL_ERROR;
723
Stefan Berger5aa2a752015-03-23 14:22:17 -0400724 get_lasa_last_ptr(entry_count, &log_area_start_address_next);
725
726 dprintf(DEBUG_tcg, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n",
727 log_area_start_address_base, log_area_start_address_next);
728
Stefan Berger7fce1d92015-11-12 10:14:45 -0500729 if (log_area_start_address_next == NULL || log_area_minimum_length == 0) {
730 tpm_set_failure();
731
Stefan Berger5aa2a752015-03-23 14:22:17 -0400732 return TCG_PC_LOGOVERFLOW;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500733 }
Stefan Berger5aa2a752015-03-23 14:22:17 -0400734
Stefan Bergere3cc6322015-11-12 10:14:47 -0500735 size = offsetof(struct pcpes, event) + event_length;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400736
737 if ((log_area_start_address_next + size - log_area_start_address_base) >
738 log_area_minimum_length) {
739 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Stefan Berger7fce1d92015-11-12 10:14:45 -0500740
741 tpm_set_failure();
742
Stefan Berger5aa2a752015-03-23 14:22:17 -0400743 return TCG_PC_LOGOVERFLOW;
744 }
745
Stefan Bergere3cc6322015-11-12 10:14:47 -0500746 pcpes->eventdatasize = event_length;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400747
Stefan Bergere3cc6322015-11-12 10:14:47 -0500748 memcpy(log_area_start_address_next, pcpes, offsetof(struct pcpes, event));
749 memcpy(log_area_start_address_next + offsetof(struct pcpes, event),
750 event, event_length);
751
752 if (entry_count)
753 (*entry_count)++;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400754
755 return 0;
756}
757
758
759static u32
760is_preboot_if_shutdown(void)
761{
762 return tpm_state.if_shutdown;
763}
764
765
766static u32
767shutdown_preboot_interface(void)
768{
769 u32 rc = 0;
770
771 if (!is_preboot_if_shutdown()) {
772 tpm_state.if_shutdown = 1;
773 } else {
774 rc = TCG_INTERFACE_SHUTDOWN;
775 }
776
777 return rc;
778}
779
780
781static void
782tpm_shutdown(void)
783{
784 reset_acpi_log();
785 shutdown_preboot_interface();
786}
787
788
789static u32
790pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
791{
792 u32 rc = 0;
793 u32 resbuflen = 0;
794 struct tpm_req_header *trh;
795 u8 locty = 0;
796 struct iovec iovec[2];
797 const u32 *tmp;
798
799 if (is_preboot_if_shutdown()) {
800 rc = TCG_INTERFACE_SHUTDOWN;
801 goto err_exit;
802 }
803
804 trh = (struct tpm_req_header *)pttti->tpmopin;
805
806 if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
807 pttti->opblength < sizeof(struct pttto) ||
808 be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) {
809 rc = TCG_INVALID_INPUT_PARA;
810 goto err_exit;
811 }
812
813 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
814
815 iovec[0].data = pttti->tpmopin;
816 tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
817 iovec[0].length = cpu_to_be32(*tmp);
818
819 iovec[1].data = NULL;
820 iovec[1].length = 0;
821
822 rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen,
823 TPM_DURATION_TYPE_LONG /* worst case */);
824 if (rc)
825 goto err_exit;
826
827 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
828 pttto->reserved = 0;
829
830err_exit:
831 if (rc != 0) {
832 pttto->opblength = 4;
833 pttto->reserved = 0;
834 }
835
836 return rc;
837}
838
839
840static u32
841tpm_extend(u8 *hash, u32 pcrindex)
842{
843 u32 rc;
844 struct pttto_extend pttto;
845 struct pttti_extend pttti = {
846 .pttti = {
847 .ipblength = sizeof(struct pttti_extend),
848 .opblength = sizeof(struct pttto_extend),
849 },
850 .req = {
851 .tag = cpu_to_be16(0xc1),
852 .totlen = cpu_to_be32(sizeof(pttti.req)),
853 .ordinal = cpu_to_be32(TPM_ORD_Extend),
854 .pcrindex = cpu_to_be32(pcrindex),
855 },
856 };
857
858 memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
859
860 rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
861
862 if (rc == 0) {
863 if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE ||
864 pttto.pttto.opblength !=
865 sizeof(struct pttto) + be32_to_cpu(pttto.rsp.totlen) ||
866 be16_to_cpu(pttto.rsp.tag) != 0xc4) {
867 rc = TCG_FATAL_COM_ERROR;
868 }
869 }
870
871 if (rc)
872 tpm_shutdown();
873
874 return rc;
875}
876
877
878static u32
879hash_all(const struct hai *hai, u8 *hash)
880{
881 if (is_preboot_if_shutdown() != 0)
882 return TCG_INTERFACE_SHUTDOWN;
883
884 if (hai->ipblength != sizeof(struct hai) ||
885 hai->hashdataptr == 0 ||
886 hai->hashdatalen == 0 ||
887 hai->algorithmid != TPM_ALG_SHA)
888 return TCG_INVALID_INPUT_PARA;
889
890 return sha1_calc((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
891}
892
Stefan Berger129c04b2015-11-12 10:14:48 -0500893static u32
894hash_log_event(const void *hashdata, u32 hashdata_length,
895 struct pcpes *pcpes,
896 const char *event, u32 event_length,
897 u16 *entry_count)
898{
899 u32 rc = 0;
900
901 if (pcpes->pcrindex >= 24)
902 return TCG_INVALID_INPUT_PARA;
903
904 if (hashdata) {
905 rc = sha1_calc(hashdata, hashdata_length, pcpes->digest);
906 if (rc)
907 return rc;
908 }
909
910 return tpm_extend_acpi_log(pcpes, event, event_length, entry_count);
911}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400912
913static u32
Stefan Berger129c04b2015-11-12 10:14:48 -0500914hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400915{
916 u32 rc = 0;
917 u16 size;
918 struct pcpes *pcpes;
919 u16 entry_count;
920
921 if (is_preboot_if_shutdown() != 0) {
922 rc = TCG_INTERFACE_SHUTDOWN;
923 goto err_exit;
924 }
925
926 size = hlei->ipblength;
927 if (size != sizeof(*hlei)) {
928 rc = TCG_INVALID_INPUT_PARA;
929 goto err_exit;
930 }
931
932 pcpes = (struct pcpes *)hlei->logdataptr;
933
934 if (pcpes->pcrindex >= 24 ||
935 pcpes->pcrindex != hlei->pcrindex ||
Stefan Berger129c04b2015-11-12 10:14:48 -0500936 pcpes->eventtype != hlei->logeventtype ||
937 hlei->logdatalen !=
938 offsetof(struct pcpes, event) + pcpes->eventdatasize) {
Stefan Berger5aa2a752015-03-23 14:22:17 -0400939 rc = TCG_INVALID_INPUT_PARA;
940 goto err_exit;
941 }
942
Stefan Berger129c04b2015-11-12 10:14:48 -0500943 rc = hash_log_event(hlei->hashdataptr, hlei->hashdatalen,
944 pcpes, (char *)&pcpes->event, pcpes->eventdatasize,
945 &entry_count);
Stefan Berger5aa2a752015-03-23 14:22:17 -0400946 if (rc)
947 goto err_exit;
948
949 /* updating the log was fine */
950 hleo->opblength = sizeof(struct hleo);
951 hleo->reserved = 0;
952 hleo->eventnumber = entry_count;
953
954err_exit:
955 if (rc != 0) {
956 hleo->opblength = 2;
957 hleo->reserved = 0;
958 }
959
960 return rc;
961}
962
Stefan Berger6c376b42015-11-12 10:14:49 -0500963static u32
964hash_log_extend_event(const void *hashdata, u32 hashdata_length,
965 struct pcpes *pcpes,
966 const char *event, u32 event_length,
967 u32 pcrindex, u16 *entry_count)
968{
969 u32 rc;
970
971 rc = hash_log_event(hashdata, hashdata_length, pcpes,
972 event, event_length, entry_count);
973 if (rc)
974 return rc;
975
976 return tpm_extend(pcpes->digest, pcrindex);
977}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400978
979static u32
Stefan Berger6c376b42015-11-12 10:14:49 -0500980hash_log_extend_event_int(const struct hleei_short *hleei_s,
981 struct hleeo *hleeo)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400982{
983 u32 rc = 0;
984 struct hleo hleo;
985 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
986 const void *logdataptr;
987 u32 logdatalen;
988 struct pcpes *pcpes;
Stefan Berger6c376b42015-11-12 10:14:49 -0500989 u32 pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400990
991 /* short or long version? */
992 switch (hleei_s->ipblength) {
993 case sizeof(struct hleei_short):
994 /* short */
995 logdataptr = hleei_s->logdataptr;
996 logdatalen = hleei_s->logdatalen;
Stefan Berger6c376b42015-11-12 10:14:49 -0500997 pcrindex = hleei_s->pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400998 break;
999
1000 case sizeof(struct hleei_long):
1001 /* long */
1002 logdataptr = hleei_l->logdataptr;
1003 logdatalen = hleei_l->logdatalen;
Stefan Berger6c376b42015-11-12 10:14:49 -05001004 pcrindex = hleei_l->pcrindex;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001005 break;
1006
1007 default:
1008 /* bad input block */
1009 rc = TCG_INVALID_INPUT_PARA;
1010 goto err_exit;
1011 }
1012
1013 pcpes = (struct pcpes *)logdataptr;
1014
Stefan Berger6c376b42015-11-12 10:14:49 -05001015 if (pcpes->pcrindex >= 24 ||
1016 pcpes->pcrindex != pcrindex ||
1017 logdatalen != offsetof(struct pcpes, event) + pcpes->eventdatasize) {
1018 rc = TCG_INVALID_INPUT_PARA;
1019 goto err_exit;
1020 }
1021
1022 rc = hash_log_extend_event(hleei_s->hashdataptr, hleei_s->hashdatalen,
1023 pcpes,
1024 (char *)&pcpes->event, pcpes->eventdatasize,
1025 pcrindex, NULL);
Stefan Berger5aa2a752015-03-23 14:22:17 -04001026 if (rc)
1027 goto err_exit;
1028
1029 hleeo->opblength = sizeof(struct hleeo);
1030 hleeo->reserved = 0;
1031 hleeo->eventnumber = hleo.eventnumber;
1032
Stefan Berger5aa2a752015-03-23 14:22:17 -04001033err_exit:
1034 if (rc != 0) {
1035 hleeo->opblength = 4;
1036 hleeo->reserved = 0;
1037 }
1038
1039 return rc;
1040
1041}
1042
1043
1044static u32
1045tss(struct ti *ti, struct to *to)
1046{
1047 u32 rc = 0;
1048
1049 if (is_preboot_if_shutdown() == 0) {
1050 rc = TCG_PC_UNSUPPORTED;
1051 } else {
1052 rc = TCG_INTERFACE_SHUTDOWN;
1053 }
1054
1055 to->opblength = sizeof(struct to);
1056 to->reserved = 0;
1057
1058 return rc;
1059}
1060
1061
1062static u32
1063compact_hash_log_extend_event(u8 *buffer,
1064 u32 info,
1065 u32 length,
1066 u32 pcrindex,
1067 u32 *edx_ptr)
1068{
1069 u32 rc = 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001070 struct pcpes pcpes = {
1071 .pcrindex = pcrindex,
1072 .eventtype = EV_COMPACT_HASH,
1073 .eventdatasize = sizeof(info),
1074 .event = info,
1075 };
Stefan Berger6c376b42015-11-12 10:14:49 -05001076 u16 entry_count;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001077
Stefan Berger6c376b42015-11-12 10:14:49 -05001078 rc = hash_log_extend_event(buffer, length,
1079 &pcpes,
1080 (char *)&pcpes.event, pcpes.eventdatasize,
1081 pcpes.pcrindex, &entry_count);
1082
Stefan Berger5aa2a752015-03-23 14:22:17 -04001083 if (rc == 0)
Stefan Berger6c376b42015-11-12 10:14:49 -05001084 *edx_ptr = entry_count;
Stefan Berger5aa2a752015-03-23 14:22:17 -04001085
1086 return rc;
1087}
1088
1089
1090void VISIBLE32FLAT
1091tpm_interrupt_handler32(struct bregs *regs)
1092{
1093 if (!CONFIG_TCGBIOS)
1094 return;
1095
1096 set_cf(regs, 0);
1097
1098 if (!has_working_tpm()) {
1099 regs->eax = TCG_GENERAL_ERROR;
1100 return;
1101 }
1102
1103 switch ((enum irq_ids)regs->al) {
1104 case TCG_StatusCheck:
1105 if (is_tpm_present() == 0) {
1106 /* no TPM available */
1107 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1108 } else {
1109 regs->eax = 0;
1110 regs->ebx = TCG_MAGIC;
1111 regs->ch = TCG_VERSION_MAJOR;
1112 regs->cl = TCG_VERSION_MINOR;
1113 regs->edx = 0x0;
1114 regs->esi = (u32)get_lasa_base_ptr(NULL);
1115 regs->edi =
1116 (u32)get_lasa_last_ptr(NULL, NULL);
1117 }
1118 break;
1119
1120 case TCG_HashLogExtendEvent:
1121 regs->eax =
Stefan Berger6c376b42015-11-12 10:14:49 -05001122 hash_log_extend_event_int(
Stefan Berger5aa2a752015-03-23 14:22:17 -04001123 (struct hleei_short *)input_buf32(regs),
1124 (struct hleeo *)output_buf32(regs));
1125 break;
1126
1127 case TCG_PassThroughToTPM:
1128 regs->eax =
1129 pass_through_to_tpm((struct pttti *)input_buf32(regs),
1130 (struct pttto *)output_buf32(regs));
1131 break;
1132
1133 case TCG_ShutdownPreBootInterface:
1134 regs->eax = shutdown_preboot_interface();
1135 break;
1136
1137 case TCG_HashLogEvent:
Stefan Berger129c04b2015-11-12 10:14:48 -05001138 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1139 (struct hleo*)output_buf32(regs));
Stefan Berger5aa2a752015-03-23 14:22:17 -04001140 break;
1141
1142 case TCG_HashAll:
1143 regs->eax =
1144 hash_all((struct hai*)input_buf32(regs),
1145 (u8 *)output_buf32(regs));
1146 break;
1147
1148 case TCG_TSS:
1149 regs->eax = tss((struct ti*)input_buf32(regs),
1150 (struct to*)output_buf32(regs));
1151 break;
1152
1153 case TCG_CompactHashLogExtendEvent:
1154 regs->eax =
1155 compact_hash_log_extend_event((u8 *)input_buf32(regs),
1156 regs->esi,
1157 regs->ecx,
1158 regs->edx,
1159 &regs->edx);
1160 break;
1161
1162 default:
1163 set_cf(regs, 1);
1164 }
1165
1166 return;
1167}
1168
Stefan Berger2aff1c12015-05-26 15:48:33 -04001169/*
1170 * Add a measurement to the log; the data at data_seg:data/length are
1171 * appended to the TCG_PCClientPCREventStruct
1172 *
1173 * Input parameters:
Stefan Berger6c376b42015-11-12 10:14:49 -05001174 * pcrindex : which PCR to extend
Stefan Berger2aff1c12015-05-26 15:48:33 -04001175 * event_type : type of event; specs section on 'Event Types'
Stefan Berger6c376b42015-11-12 10:14:49 -05001176 * event : pointer to info (e.g., string) to be added to log as-is
1177 * event_length: length of the event
1178 * hashdata : pointer to the data to be hashed
1179 * hashdata_length: length of the data to be hashed
Stefan Berger2aff1c12015-05-26 15:48:33 -04001180 */
1181static u32
Stefan Berger6c376b42015-11-12 10:14:49 -05001182tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
1183 const char *event, u32 event_length,
1184 const u8 *hashdata, u32 hashdata_length)
Stefan Berger2aff1c12015-05-26 15:48:33 -04001185{
Stefan Berger6c376b42015-11-12 10:14:49 -05001186 struct pcpes pcpes = {
1187 .pcrindex = pcrindex,
1188 .eventtype = event_type,
1189 };
1190 u16 entry_count;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001191
Stefan Berger6c376b42015-11-12 10:14:49 -05001192 return hash_log_extend_event(hashdata, hashdata_length, &pcpes,
1193 event, event_length, pcrindex,
1194 &entry_count);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001195}
1196
1197
1198/*
1199 * Add a measurement to the list of measurements
1200 * pcrIndex : PCR to be extended
1201 * event_type : type of event; specs section on 'Event Types'
1202 * data : additional parameter; used as parameter for
1203 * 'action index'
1204 */
1205static u32
1206tpm_add_measurement(u32 pcrIndex,
1207 u16 event_type,
1208 const char *string)
1209{
1210 u32 rc;
1211 u32 len;
1212
1213 switch (event_type) {
1214 case EV_SEPARATOR:
1215 len = sizeof(evt_separator);
1216 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1217 (char *)NULL, 0,
1218 (u8 *)evt_separator, len);
1219 break;
1220
1221 case EV_ACTION:
1222 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1223 string, strlen(string),
1224 (u8 *)string, strlen(string));
1225 break;
1226
1227 default:
1228 rc = TCG_INVALID_INPUT_PARA;
1229 }
1230
1231 return rc;
1232}
1233
1234
1235static u32
1236tpm_calling_int19h(void)
1237{
1238 if (!CONFIG_TCGBIOS)
1239 return 0;
1240
1241 if (!has_working_tpm())
1242 return TCG_GENERAL_ERROR;
1243
1244 return tpm_add_measurement(4, EV_ACTION,
1245 "Calling INT 19h");
1246}
1247
1248/*
1249 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
1250 */
1251u32
1252tpm_add_event_separators(void)
1253{
1254 u32 rc;
1255 u32 pcrIndex = 0;
1256
1257 if (!CONFIG_TCGBIOS)
1258 return 0;
1259
1260 if (!has_working_tpm())
1261 return TCG_GENERAL_ERROR;
1262
1263 while (pcrIndex <= 7) {
1264 rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
1265 if (rc)
1266 break;
1267 pcrIndex ++;
1268 }
1269
1270 return rc;
1271}
1272
1273
1274/*
1275 * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
1276 * the list of measurements.
1277 */
1278static u32
1279tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
1280{
1281 const char *string;
1282
1283 if (!CONFIG_TCGBIOS)
1284 return 0;
1285
1286 if (!has_working_tpm())
1287 return TCG_GENERAL_ERROR;
1288
1289 switch (bootcd) {
1290 case 0:
1291 switch (bootdrv) {
1292 case 0:
1293 string = "Booting BCV device 00h (Floppy)";
1294 break;
1295
1296 case 0x80:
1297 string = "Booting BCV device 80h (HDD)";
1298 break;
1299
1300 default:
1301 string = "Booting unknown device";
1302 break;
1303 }
1304
1305 break;
1306
1307 default:
1308 string = "Booting from CD ROM device";
1309 }
1310
1311 return tpm_add_measurement_to_log(4, EV_ACTION,
1312 string, strlen(string),
1313 (u8 *)string, strlen(string));
1314}
1315
1316
1317/*
1318 * Add measurement to the log about option rom scan
1319 */
1320u32
1321tpm_start_option_rom_scan(void)
1322{
1323 if (!CONFIG_TCGBIOS)
1324 return 0;
1325
1326 if (!has_working_tpm())
1327 return TCG_GENERAL_ERROR;
1328
1329 return tpm_add_measurement(2, EV_ACTION,
1330 "Start Option ROM Scan");
1331}
1332
1333
1334/*
1335 * Add measurement to the log about an option rom
1336 */
1337u32
1338tpm_option_rom(const void *addr, u32 len)
1339{
1340 if (!CONFIG_TCGBIOS)
1341 return 0;
1342
1343 if (!has_working_tpm())
1344 return TCG_GENERAL_ERROR;
1345
1346 u32 rc;
1347 struct pcctes_romex pcctes = {
1348 .eventid = 7,
1349 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
1350 };
1351
1352 rc = sha1((const u8 *)addr, len, pcctes.digest);
1353 if (rc)
1354 return rc;
1355
1356 return tpm_add_measurement_to_log(2,
1357 EV_EVENT_TAG,
1358 (const char *)&pcctes, sizeof(pcctes),
1359 (u8 *)&pcctes, sizeof(pcctes));
1360}
1361
1362
1363u32
1364tpm_smbios_measure(void)
1365{
1366 if (!CONFIG_TCGBIOS)
1367 return 0;
1368
1369 if (!has_working_tpm())
1370 return TCG_GENERAL_ERROR;
1371
1372 u32 rc;
1373 struct pcctes pcctes = {
1374 .eventid = 1,
1375 .eventdatasize = SHA1_BUFSIZE,
1376 };
1377 struct smbios_entry_point *sep = SMBiosAddr;
1378
1379 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
1380
1381 if (!sep)
1382 return 0;
1383
1384 rc = sha1((const u8 *)sep->structure_table_address,
1385 sep->structure_table_length, pcctes.digest);
1386 if (rc)
1387 return rc;
1388
1389 return tpm_add_measurement_to_log(1,
1390 EV_EVENT_TAG,
1391 (const char *)&pcctes, sizeof(pcctes),
1392 (u8 *)&pcctes, sizeof(pcctes));
1393}
1394
1395
1396/*
1397 * Add a measurement related to Initial Program Loader to the log.
1398 * Creates two log entries.
1399 *
1400 * Input parameter:
1401 * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
1402 * addr : address where the IP data are located
1403 * length : IP data length in bytes
1404 */
1405static u32
1406tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
1407{
1408 u32 rc;
1409 const char *string;
1410
1411 switch (bootcd) {
1412 case IPL_EL_TORITO_1:
1413 /* specs: see section 'El Torito' */
1414 string = "EL TORITO IPL";
1415 rc = tpm_add_measurement_to_log(4, EV_IPL,
1416 string, strlen(string),
1417 addr, length);
1418 break;
1419
1420 case IPL_EL_TORITO_2:
1421 /* specs: see section 'El Torito' */
1422 string = "BOOT CATALOG";
1423 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1424 string, strlen(string),
1425 addr, length);
1426 break;
1427
1428 default:
1429 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1430 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
1431 string = "MBR";
1432 rc = tpm_add_measurement_to_log(4, EV_IPL,
1433 string, strlen(string),
1434 addr, 0x1b8);
1435
1436 if (rc)
1437 break;
1438
1439 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
1440 string = "MBR PARTITION_TABLE";
1441 rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1442 string, strlen(string),
1443 addr + 0x1b8, 0x48);
1444 }
1445
1446 return rc;
1447}
1448
1449u32
1450tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1451{
1452 if (!CONFIG_TCGBIOS)
1453 return 0;
1454
1455 if (!has_working_tpm())
1456 return TCG_GENERAL_ERROR;
1457
1458 u32 rc = tpm_add_bootdevice(0, bootdrv);
1459 if (rc)
1460 return rc;
1461
1462 return tpm_ipl(IPL_BCV, addr, length);
1463}
1464
1465u32
1466tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1467{
1468 if (!CONFIG_TCGBIOS)
1469 return 0;
1470
1471 if (!has_working_tpm())
1472 return TCG_GENERAL_ERROR;
1473
1474 u32 rc = tpm_add_bootdevice(1, bootdrv);
1475 if (rc)
1476 return rc;
1477
1478 return tpm_ipl(IPL_EL_TORITO_1, addr, length);
1479}
1480
1481u32
1482tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1483{
1484 if (!CONFIG_TCGBIOS)
1485 return 0;
1486
1487 if (!has_working_tpm())
1488 return TCG_GENERAL_ERROR;
1489
1490 u32 rc = tpm_add_bootdevice(1, 0);
1491 if (rc)
1492 return rc;
1493
1494 return tpm_ipl(IPL_EL_TORITO_2, addr, length);
1495}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001496
Kevin O'Connord6aca442015-06-10 11:00:17 -04001497void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001498tpm_s3_resume(void)
1499{
1500 u32 rc;
1501 u32 returnCode;
1502
1503 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001504 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001505
1506 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001507 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001508
1509 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1510
Stefan Berger5aa2a752015-03-23 14:22:17 -04001511 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001512 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -04001513 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001514
1515 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
1516 returnCode);
1517
1518 if (rc || returnCode)
1519 goto err_exit;
1520
Kevin O'Connord6aca442015-06-10 11:00:17 -04001521 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001522
1523err_exit:
1524 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1525
Stefan Berger7fce1d92015-11-12 10:14:45 -05001526 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001527}