blob: 73ff1f375cbd1d5306167ca34a109c0984d90f91 [file] [log] [blame]
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001// Implementation of the TCG BIOS extension according to the specification
2// described in
3// https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
4//
5// Copyright (C) 2006-2011, 2014 IBM Corporation
6//
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
25
26
27static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR };
28static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE };
29
30static const u8 PhysicalPresence_CMD_ENABLE[2] = { 0x00, 0x20 };
31static const u8 PhysicalPresence_CMD_DISABLE[2] = { 0x01, 0x00 };
32static const u8 PhysicalPresence_PRESENT[2] = { 0x00, 0x08 };
33static const u8 PhysicalPresence_NOT_PRESENT_LOCK[2] = { 0x00, 0x14 };
34
35static const u8 CommandFlag_FALSE[1] = { 0x00 };
36static const u8 CommandFlag_TRUE[1] = { 0x01 };
37
38static const u8 GetCapability_Permanent_Flags[12] = {
39 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
40 0x00, 0x00, 0x01, 0x08
41};
42
43static const u8 GetCapability_OwnerAuth[12] = {
44 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
45 0x00, 0x00, 0x01, 0x11
46};
47
48static const u8 GetCapability_Timeouts[] = {
49 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
50 0x00, 0x00, 0x01, 0x15
51};
52
53static const u8 GetCapability_Durations[] = {
54 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
55 0x00, 0x00, 0x01, 0x20
56};
57
58
59#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr)
60
61
62/* helper functions */
63
64static inline void *input_buf32(struct bregs *regs)
65{
66 return MAKE_FLATPTR(regs->es, regs->di);
67}
68
69static inline void *output_buf32(struct bregs *regs)
70{
71 return MAKE_FLATPTR(regs->ds, regs->si);
72}
73
74
75typedef struct {
76 u8 tpm_probed:1;
77 u8 tpm_found:1;
78 u8 tpm_working:1;
79 u8 if_shutdown:1;
80 u8 tpm_driver_to_use:4;
81} tpm_state_t;
82
83
84static tpm_state_t tpm_state = {
85 .tpm_driver_to_use = TPM_INVALID_DRIVER,
86};
87
88
89/********************************************************
90 Extensions for TCG-enabled BIOS
91 *******************************************************/
92
93
94static u32
95is_tpm_present(void)
96{
97 u32 rc = 0;
98 unsigned int i;
99
100 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
101 struct tpm_driver *td = &tpm_drivers[i];
102 if (td->probe() != 0) {
103 td->init();
104 tpm_state.tpm_driver_to_use = i;
105 rc = 1;
106 break;
107 }
108 }
109
110 return rc;
111}
112
113static void
114probe_tpm(void)
115{
116 if (!tpm_state.tpm_probed) {
117 tpm_state.tpm_probed = 1;
118 tpm_state.tpm_found = (is_tpm_present() != 0);
119 tpm_state.tpm_working = tpm_state.tpm_found;
120 }
121}
122
123static int
124has_working_tpm(void)
125{
126 probe_tpm();
127
128 return tpm_state.tpm_working;
129}
130
131static struct tcpa_descriptor_rev2 *
132find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
133{
134 u32 ctr = 0;
135 struct tcpa_descriptor_rev2 *tcpa = NULL;
136 struct rsdt_descriptor *rsdt;
137 u32 length;
138 u16 off;
139
140 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
141 if (!rsdt)
142 return NULL;
143
144 length = rsdt->length;
145 off = offsetof(struct rsdt_descriptor, entry);
146
147 while ((off + sizeof(rsdt->entry[0])) <= length) {
148 /* try all pointers to structures */
149 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
150
151 /* valid TCPA ACPI table ? */
152 if (tcpa->signature == TCPA_SIGNATURE &&
153 checksum((u8 *)tcpa, tcpa->length) == 0)
154 break;
155
156 tcpa = NULL;
157 off += sizeof(rsdt->entry[0]);
158 ctr++;
159 }
160
161 return tcpa;
162}
163
164
165static struct tcpa_descriptor_rev2 *
166find_tcpa_table(void)
167{
168 struct tcpa_descriptor_rev2 *tcpa = NULL;
169 struct rsdp_descriptor *rsdp = RsdpAddr;
170
171 if (rsdp)
172 tcpa = find_tcpa_by_rsdp(rsdp);
173 else
174 tpm_state.if_shutdown = 1;
175
176 if (!rsdp)
177 dprintf(DEBUG_tcg,
178 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
179 else if (!tcpa)
180 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
181
182 return tcpa;
183}
184
185
186static u8 *
187get_lasa_base_ptr(u32 *log_area_minimum_length)
188{
189 u8 *log_area_start_address = 0;
190 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
191
192 if (tcpa) {
193 log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
194 if (log_area_minimum_length)
195 *log_area_minimum_length = tcpa->log_area_minimum_length;
196 }
197
198 return log_area_start_address;
199}
200
201
202/* clear the ACPI log */
203static void
204reset_acpi_log(void)
205{
206 u32 log_area_minimum_length;
207 u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
208
209 if (log_area_start_address)
210 memset(log_area_start_address, 0x0, log_area_minimum_length);
211}
212
213
214/*
215 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
216 where the TCPA table is.
217 */
218static void
219tpm_acpi_init(void)
220{
221 tpm_state.if_shutdown = 0;
222 tpm_state.tpm_probed = 0;
223 tpm_state.tpm_found = 0;
224 tpm_state.tpm_working = 0;
225
226 if (!has_working_tpm()) {
227 tpm_state.if_shutdown = 1;
228 return;
229 }
230
231 reset_acpi_log();
232}
233
234
235static u32
236transmit(u8 locty, const struct iovec iovec[],
237 u8 *respbuffer, u32 *respbufferlen,
238 enum tpmDurationType to_t)
239{
240 u32 rc = 0;
241 u32 irc;
242 struct tpm_driver *td;
243 unsigned int i;
244
245 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
246 return TCG_FATAL_COM_ERROR;
247
248 td = &tpm_drivers[tpm_state.tpm_driver_to_use];
249
250 irc = td->activate(locty);
251 if (irc != 0) {
252 /* tpm could not be activated */
253 return TCG_FATAL_COM_ERROR;
254 }
255
256 for (i = 0; iovec[i].length; i++) {
257 irc = td->senddata(iovec[i].data,
258 iovec[i].length);
259 if (irc != 0)
260 return TCG_FATAL_COM_ERROR;
261 }
262
263 irc = td->waitdatavalid();
264 if (irc != 0)
265 return TCG_FATAL_COM_ERROR;
266
267 irc = td->waitrespready(to_t);
268 if (irc != 0)
269 return TCG_FATAL_COM_ERROR;
270
271 irc = td->readresp(respbuffer,
272 respbufferlen);
273 if (irc != 0)
274 return TCG_FATAL_COM_ERROR;
275
276 td->ready();
277
278 return rc;
279}
280
281
282/*
283 * Send a TPM command with the given ordinal. Append the given buffer
284 * containing all data in network byte order to the command (this is
285 * the custom part per command) and expect a response of the given size.
286 * If a buffer is provided, the response will be copied into it.
287 */
288static u32
289build_and_send_cmd_od(u32 ordinal, const u8 *append, u32 append_size,
290 u8 *resbuffer, u32 return_size, u32 *returnCode,
291 const u8 *otherdata, u32 otherdata_size,
292 enum tpmDurationType to_t)
293{
294#define MAX_APPEND_SIZE 12
295#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags)
296 u32 rc;
297 u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE];
298 u8 obuffer[MAX_RESPONSE_SIZE];
299 struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer;
300 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
301 u8 locty = 0;
302 struct iovec iovec[3];
303 u32 obuffer_len = sizeof(obuffer);
304 u32 idx = 1;
305
306 if (append_size > MAX_APPEND_SIZE ||
307 return_size > MAX_RESPONSE_SIZE) {
308 dprintf(DEBUG_tcg, "TCGBIOS: size of requested buffers too big.");
309 return TCG_FIRMWARE_ERROR;
310 }
311
312 iovec[0].data = trqh;
313 iovec[0].length = TPM_REQ_HEADER_SIZE + append_size;
314
315 if (otherdata) {
316 iovec[1].data = (void *)otherdata;
317 iovec[1].length = otherdata_size;
318 idx = 2;
319 }
320
321 iovec[idx].data = NULL;
322 iovec[idx].length = 0;
323
324 memset(ibuffer, 0x0, sizeof(ibuffer));
325 memset(obuffer, 0x0, sizeof(obuffer));
326
327 trqh->tag = cpu_to_be16(0xc1);
328 trqh->totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size + otherdata_size);
329 trqh->ordinal = cpu_to_be32(ordinal);
330
331 if (append_size)
332 memcpy((char *)trqh + sizeof(*trqh),
333 append, append_size);
334
335 rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
336 if (rc)
337 return rc;
338
339 *returnCode = be32_to_cpu(trsh->errcode);
340
341 if (resbuffer)
342 memcpy(resbuffer, trsh, return_size);
343
344 return 0;
345}
346
347
348static u32
349build_and_send_cmd(u32 ordinal, const u8 *append, u32 append_size,
350 u8 *resbuffer, u32 return_size, u32 *returnCode,
351 enum tpmDurationType to_t)
352{
353 return build_and_send_cmd_od(ordinal, append, append_size,
354 resbuffer, return_size, returnCode,
355 NULL, 0, to_t);
356}
357
358
359static u32
360determine_timeouts(void)
361{
362 u32 rc;
363 u32 returnCode;
364 struct tpm_res_getcap_timeouts timeouts;
365 struct tpm_res_getcap_durations durations;
366 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
367 u32 i;
368
369 rc = build_and_send_cmd(TPM_ORD_GetCapability,
370 GetCapability_Timeouts,
371 sizeof(GetCapability_Timeouts),
372 (u8 *)&timeouts,
373 sizeof(struct tpm_res_getcap_timeouts),
374 &returnCode, TPM_DURATION_TYPE_SHORT);
375
376 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
377 " = 0x%08x\n", returnCode);
378
379 if (rc || returnCode)
380 goto err_exit;
381
382 rc = build_and_send_cmd(TPM_ORD_GetCapability,
383 GetCapability_Durations,
384 sizeof(GetCapability_Durations),
385 (u8 *)&durations,
386 sizeof(struct tpm_res_getcap_durations),
387 &returnCode, TPM_DURATION_TYPE_SHORT);
388
389 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
390 " = 0x%08x\n", returnCode);
391
392 if (rc || returnCode)
393 goto err_exit;
394
395 for (i = 0; i < 3; i++)
396 durations.durations[i] = be32_to_cpu(durations.durations[i]);
397
398 for (i = 0; i < 4; i++)
399 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
400
401 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
402 timeouts.timeouts[0],
403 timeouts.timeouts[1],
404 timeouts.timeouts[2],
405 timeouts.timeouts[3]);
406
407 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
408 durations.durations[0],
409 durations.durations[1],
410 durations.durations[2]);
411
412
413 td->set_timeouts(timeouts.timeouts, durations.durations);
414
415 return 0;
416
417err_exit:
418 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
419
420 tpm_state.tpm_working = 0;
421 if (rc)
422 return rc;
423 return TCG_TCG_COMMAND_ERROR;
424}
425
426
427static u32
428tpm_startup(void)
429{
430 u32 rc;
431 u32 returnCode;
432
433 if (!has_working_tpm())
434 return TCG_GENERAL_ERROR;
435
436 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
437 rc = build_and_send_cmd(TPM_ORD_Startup,
438 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
439 NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
440
441 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
442 returnCode);
443
444 if (CONFIG_COREBOOT) {
445 /* with other firmware on the system the TPM may already have been
446 * initialized
447 */
448 if (returnCode == TPM_INVALID_POSTINIT)
449 returnCode = 0;
450 }
451
452 if (rc || returnCode)
453 goto err_exit;
454
455 rc = build_and_send_cmd(TPM_ORD_SelfTestFull, NULL, 0,
456 NULL, 10, &returnCode, TPM_DURATION_TYPE_LONG);
457
458 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
459 returnCode);
460
461 if (rc || returnCode)
462 goto err_exit;
463
464 rc = build_and_send_cmd(TSC_ORD_ResetEstablishmentBit, NULL, 0,
465 NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
466
467 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
468 returnCode);
469
470 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
471 goto err_exit;
472
473 rc = determine_timeouts();
474 if (rc)
475 goto err_exit;
476
477 return 0;
478
479err_exit:
480 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
481
482 tpm_state.tpm_working = 0;
483 if (rc)
484 return rc;
485 return TCG_TCG_COMMAND_ERROR;
486}
487
488
489u32
490tpm_start(void)
491{
492 if (!CONFIG_TCGBIOS)
493 return 0;
494
495 tpm_acpi_init();
496
497 return tpm_startup();
498}
499
500
501u32
502tpm_leave_bios(void)
503{
504 u32 rc;
505 u32 returnCode;
506
507 if (!CONFIG_TCGBIOS)
508 return 0;
509
510 if (!has_working_tpm())
511 return TCG_GENERAL_ERROR;
512
513 rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
514 PhysicalPresence_CMD_ENABLE,
515 sizeof(PhysicalPresence_CMD_ENABLE),
516 NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
517 if (rc || returnCode)
518 goto err_exit;
519
520 rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
521 PhysicalPresence_NOT_PRESENT_LOCK,
522 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
523 NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
524 if (rc || returnCode)
525 goto err_exit;
526
527 return 0;
528
529err_exit:
530 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
531
532 tpm_state.tpm_working = 0;
533 if (rc)
534 return rc;
535 return TCG_TCG_COMMAND_ERROR;
536}
537
538
539u32
540tpm_s3_resume(void)
541{
542 u32 rc;
543 u32 returnCode;
544
545 if (!CONFIG_TCGBIOS)
546 return 0;
547
548 if (!has_working_tpm())
549 return TCG_GENERAL_ERROR;
550
551 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
552
553 rc = build_and_send_cmd(TPM_ORD_Startup,
554 Startup_ST_STATE, sizeof(Startup_ST_STATE),
555 NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
556
557 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
558 returnCode);
559
560 if (rc || returnCode)
561 goto err_exit;
562
563 return 0;
564
565err_exit:
566 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
567
568 tpm_state.tpm_working = 0;
569 if (rc)
570 return rc;
571 return TCG_TCG_COMMAND_ERROR;
572}