These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / seabios / src / tcgbios.c
1 //  Implementation of the TCG BIOS extension according to the specification
2 //  described in specs found at
3 //  http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
4 //
5 //  Copyright (C) 2006-2011, 2014, 2015 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 #include "sha1.h" // sha1
26 #include "fw/paravirt.h" // runningOnXen
27 #include "std/smbios.h"
28
29 static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
30 static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
31
32 static const u8 PhysicalPresence_CMD_ENABLE[]  = { 0x00, 0x20 };
33 static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
34 static const u8 PhysicalPresence_PRESENT[]     = { 0x00, 0x08 };
35 static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
36
37 static const u8 CommandFlag_FALSE[1] = { 0x00 };
38 static const u8 CommandFlag_TRUE[1]  = { 0x01 };
39
40 static const u8 GetCapability_Permanent_Flags[] = {
41     0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
42     0x00, 0x00, 0x01, 0x08
43 };
44
45 static const u8 GetCapability_OwnerAuth[] = {
46     0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
47     0x00, 0x00, 0x01, 0x11
48 };
49
50 static const u8 GetCapability_Timeouts[] = {
51     0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
52     0x00, 0x00, 0x01, 0x15
53 };
54
55 static const u8 GetCapability_Durations[] = {
56     0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
57     0x00, 0x00, 0x01, 0x20
58 };
59
60 static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
61
62
63 #define RSDP_CAST(ptr)   ((struct rsdp_descriptor *)ptr)
64
65 /* local function prototypes */
66
67 static u32 tpm_calling_int19h(void);
68 static u32 tpm_add_event_separators(void);
69 static u32 tpm_start_option_rom_scan(void);
70 static u32 tpm_smbios_measure(void);
71
72 /* helper functions */
73
74 static inline void *input_buf32(struct bregs *regs)
75 {
76     return MAKE_FLATPTR(regs->es, regs->di);
77 }
78
79 static inline void *output_buf32(struct bregs *regs)
80 {
81     return MAKE_FLATPTR(regs->ds, regs->si);
82 }
83
84
85 typedef struct {
86     u8            tpm_probed:1;
87     u8            tpm_found:1;
88     u8            tpm_working:1;
89     u8            if_shutdown:1;
90     u8            tpm_driver_to_use:4;
91 } tpm_state_t;
92
93
94 static tpm_state_t tpm_state = {
95     .tpm_driver_to_use = TPM_INVALID_DRIVER,
96 };
97
98
99 /********************************************************
100   Extensions for TCG-enabled BIOS
101  *******************************************************/
102
103
104 static u32
105 is_tpm_present(void)
106 {
107     u32 rc = 0;
108     unsigned int i;
109
110     for (i = 0; i < TPM_NUM_DRIVERS; i++) {
111         struct tpm_driver *td = &tpm_drivers[i];
112         if (td->probe() != 0) {
113             td->init();
114             tpm_state.tpm_driver_to_use = i;
115             rc = 1;
116             break;
117         }
118     }
119
120     return rc;
121 }
122
123 static void
124 probe_tpm(void)
125 {
126     if (!tpm_state.tpm_probed) {
127         tpm_state.tpm_probed = 1;
128         tpm_state.tpm_found = (is_tpm_present() != 0);
129         tpm_state.tpm_working = tpm_state.tpm_found;
130     }
131 }
132
133 static int
134 has_working_tpm(void)
135 {
136     probe_tpm();
137
138     return tpm_state.tpm_working;
139 }
140
141 static struct tcpa_descriptor_rev2 *
142 find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
143 {
144     u32 ctr = 0;
145     struct tcpa_descriptor_rev2 *tcpa = NULL;
146     struct rsdt_descriptor *rsdt;
147     u32 length;
148     u16 off;
149
150     rsdt   = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
151     if (!rsdt)
152         return NULL;
153
154     length = rsdt->length;
155     off = offsetof(struct rsdt_descriptor, entry);
156
157     while ((off + sizeof(rsdt->entry[0])) <= length) {
158         /* try all pointers to structures */
159         tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
160
161         /* valid TCPA ACPI table ? */
162         if (tcpa->signature == TCPA_SIGNATURE &&
163             checksum((u8 *)tcpa, tcpa->length) == 0)
164             break;
165
166         tcpa = NULL;
167         off += sizeof(rsdt->entry[0]);
168         ctr++;
169     }
170
171     return tcpa;
172 }
173
174
175 static struct tcpa_descriptor_rev2 *
176 find_tcpa_table(void)
177 {
178     struct tcpa_descriptor_rev2 *tcpa = NULL;
179     struct rsdp_descriptor *rsdp = RsdpAddr;
180
181     if (rsdp)
182         tcpa = find_tcpa_by_rsdp(rsdp);
183     else
184         tpm_state.if_shutdown = 1;
185
186     if (!rsdp)
187         dprintf(DEBUG_tcg,
188                 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
189     else if (!tcpa)
190         dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
191
192     return tcpa;
193 }
194
195
196 static u8 *
197 get_lasa_base_ptr(u32 *log_area_minimum_length)
198 {
199     u8 *log_area_start_address = 0;
200     struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
201
202     if (tcpa) {
203         log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
204         if (log_area_minimum_length)
205             *log_area_minimum_length = tcpa->log_area_minimum_length;
206     }
207
208     return log_area_start_address;
209 }
210
211
212 /* clear the ACPI log */
213 static void
214 reset_acpi_log(void)
215 {
216     u32 log_area_minimum_length;
217     u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
218
219     if (log_area_start_address)
220         memset(log_area_start_address, 0x0, log_area_minimum_length);
221 }
222
223
224 /*
225    initialize the TCPA ACPI subsystem; find the ACPI tables and determine
226    where the TCPA table is.
227  */
228 static void
229 tpm_acpi_init(void)
230 {
231     tpm_state.if_shutdown = 0;
232     tpm_state.tpm_probed = 0;
233     tpm_state.tpm_found = 0;
234     tpm_state.tpm_working = 0;
235
236     if (!has_working_tpm()) {
237         tpm_state.if_shutdown = 1;
238         return;
239     }
240
241     reset_acpi_log();
242 }
243
244
245 static u32
246 transmit(u8 locty, const struct iovec iovec[],
247          u8 *respbuffer, u32 *respbufferlen,
248          enum tpmDurationType to_t)
249 {
250     u32 rc = 0;
251     u32 irc;
252     struct tpm_driver *td;
253     unsigned int i;
254
255     if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
256         return TCG_FATAL_COM_ERROR;
257
258     td = &tpm_drivers[tpm_state.tpm_driver_to_use];
259
260     irc = td->activate(locty);
261     if (irc != 0) {
262         /* tpm could not be activated */
263         return TCG_FATAL_COM_ERROR;
264     }
265
266     for (i = 0; iovec[i].length; i++) {
267         irc = td->senddata(iovec[i].data,
268                            iovec[i].length);
269         if (irc != 0)
270             return TCG_FATAL_COM_ERROR;
271     }
272
273     irc = td->waitdatavalid();
274     if (irc != 0)
275         return TCG_FATAL_COM_ERROR;
276
277     irc = td->waitrespready(to_t);
278     if (irc != 0)
279         return TCG_FATAL_COM_ERROR;
280
281     irc = td->readresp(respbuffer,
282                        respbufferlen);
283     if (irc != 0)
284         return TCG_FATAL_COM_ERROR;
285
286     td->ready();
287
288     return rc;
289 }
290
291
292 /*
293  * Send a TPM command with the given ordinal. Append the given buffer
294  * containing all data in network byte order to the command (this is
295  * the custom part per command) and expect a response of the given size.
296  * If a buffer is provided, the response will be copied into it.
297  */
298 static u32
299 build_and_send_cmd_od(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
300                       u8 *resbuffer, u32 return_size, u32 *returnCode,
301                       const u8 *otherdata, u32 otherdata_size,
302                       enum tpmDurationType to_t)
303 {
304 #define MAX_APPEND_SIZE   sizeof(GetCapability_Timeouts)
305 #define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags)
306     u32 rc;
307     u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE];
308     u8 obuffer[MAX_RESPONSE_SIZE];
309     struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer;
310     struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
311     struct iovec iovec[3];
312     u32 obuffer_len = sizeof(obuffer);
313     u32 idx = 1;
314
315     if (append_size > MAX_APPEND_SIZE ||
316         return_size > MAX_RESPONSE_SIZE) {
317         dprintf(DEBUG_tcg, "TCGBIOS: size of requested buffers too big.");
318         return TCG_FIRMWARE_ERROR;
319     }
320
321     iovec[0].data   = trqh;
322     iovec[0].length = TPM_REQ_HEADER_SIZE + append_size;
323
324     if (otherdata) {
325         iovec[1].data   = (void *)otherdata;
326         iovec[1].length = otherdata_size;
327         idx = 2;
328     }
329
330     iovec[idx].data   = NULL;
331     iovec[idx].length = 0;
332
333     memset(ibuffer, 0x0, sizeof(ibuffer));
334     memset(obuffer, 0x0, sizeof(obuffer));
335
336     trqh->tag     = cpu_to_be16(TPM_TAG_RQU_CMD);
337     trqh->totlen  = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size +
338                                 otherdata_size);
339     trqh->ordinal = cpu_to_be32(ordinal);
340
341     if (append_size)
342         memcpy((char *)trqh + sizeof(*trqh),
343                append, append_size);
344
345     rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
346     if (rc)
347         return rc;
348
349     *returnCode = be32_to_cpu(trsh->errcode);
350
351     if (resbuffer)
352         memcpy(resbuffer, trsh, return_size);
353
354     return 0;
355 }
356
357
358 static u32
359 build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
360                    u8 *resbuffer, u32 return_size, u32 *returnCode,
361                    enum tpmDurationType to_t)
362 {
363     return build_and_send_cmd_od(locty, ordinal, append, append_size,
364                                  resbuffer, return_size, returnCode,
365                                  NULL, 0, to_t);
366 }
367
368
369 static u32
370 determine_timeouts(void)
371 {
372     u32 rc;
373     u32 returnCode;
374     struct tpm_res_getcap_timeouts timeouts;
375     struct tpm_res_getcap_durations durations;
376     struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
377     u32 i;
378
379     rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
380                             GetCapability_Timeouts,
381                             sizeof(GetCapability_Timeouts),
382                             (u8 *)&timeouts, sizeof(timeouts),
383                             &returnCode, TPM_DURATION_TYPE_SHORT);
384
385     dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
386             " = 0x%08x\n", returnCode);
387
388     if (rc || returnCode)
389         goto err_exit;
390
391     rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
392                             GetCapability_Durations,
393                             sizeof(GetCapability_Durations),
394                             (u8 *)&durations, sizeof(durations),
395                             &returnCode, TPM_DURATION_TYPE_SHORT);
396
397     dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
398             " = 0x%08x\n", returnCode);
399
400     if (rc || returnCode)
401         goto err_exit;
402
403     for (i = 0; i < 3; i++)
404         durations.durations[i] = be32_to_cpu(durations.durations[i]);
405
406     for (i = 0; i < 4; i++)
407         timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
408
409     dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
410             timeouts.timeouts[0],
411             timeouts.timeouts[1],
412             timeouts.timeouts[2],
413             timeouts.timeouts[3]);
414
415     dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
416             durations.durations[0],
417             durations.durations[1],
418             durations.durations[2]);
419
420
421     td->set_timeouts(timeouts.timeouts, durations.durations);
422
423     return 0;
424
425 err_exit:
426     dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
427
428     tpm_state.tpm_working = 0;
429     if (rc)
430         return rc;
431     return TCG_TCG_COMMAND_ERROR;
432 }
433
434
435 static u32
436 tpm_startup(void)
437 {
438     u32 rc;
439     u32 returnCode;
440
441     if (!has_working_tpm())
442         return TCG_GENERAL_ERROR;
443
444     dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
445     rc = build_and_send_cmd(0, TPM_ORD_Startup,
446                             Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
447                             NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
448
449     dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
450             returnCode);
451
452     if (CONFIG_COREBOOT) {
453         /* with other firmware on the system the TPM may already have been
454          * initialized
455          */
456         if (returnCode == TPM_INVALID_POSTINIT)
457             returnCode = 0;
458     }
459
460     if (rc || returnCode)
461         goto err_exit;
462
463     rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
464                             NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
465
466     dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
467             returnCode);
468
469     if (rc || returnCode)
470         goto err_exit;
471
472     rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
473                             NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
474
475     dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
476             returnCode);
477
478     if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
479         goto err_exit;
480
481     rc = determine_timeouts();
482     if (rc)
483         goto err_exit;
484
485     rc = tpm_smbios_measure();
486     if (rc)
487         goto err_exit;
488
489     rc = tpm_start_option_rom_scan();
490     if (rc)
491         goto err_exit;
492
493     return 0;
494
495 err_exit:
496     dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
497
498     tpm_state.tpm_working = 0;
499     if (rc)
500         return rc;
501     return TCG_TCG_COMMAND_ERROR;
502 }
503
504
505 void
506 tpm_setup(void)
507 {
508     if (!CONFIG_TCGBIOS)
509         return;
510
511     tpm_acpi_init();
512     if (runningOnXen())
513         return;
514
515     tpm_startup();
516 }
517
518
519 void
520 tpm_prepboot(void)
521 {
522     u32 rc;
523     u32 returnCode;
524
525     if (!CONFIG_TCGBIOS)
526         return;
527
528     if (!has_working_tpm())
529         return;
530
531     rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
532                             PhysicalPresence_CMD_ENABLE,
533                             sizeof(PhysicalPresence_CMD_ENABLE),
534                             NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
535     if (rc || returnCode)
536         goto err_exit;
537
538     rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
539                             PhysicalPresence_NOT_PRESENT_LOCK,
540                             sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
541                             NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
542     if (rc || returnCode)
543         goto err_exit;
544
545     rc = tpm_calling_int19h();
546     if (rc)
547         goto err_exit;
548
549     rc = tpm_add_event_separators();
550     if (rc)
551         goto err_exit;
552
553     return;
554
555 err_exit:
556     dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
557
558     tpm_state.tpm_working = 0;
559 }
560
561 static int
562 is_valid_pcpes(struct pcpes *pcpes)
563 {
564     return (pcpes->eventtype != 0);
565 }
566
567
568 static u8 *
569 get_lasa_last_ptr(u16 *entry_count, u8 **log_area_start_address_next)
570 {
571     struct pcpes *pcpes;
572     u32 log_area_minimum_length = 0;
573     u8 *log_area_start_address_base =
574         get_lasa_base_ptr(&log_area_minimum_length);
575     u8 *log_area_start_address_last = NULL;
576     u8 *end = log_area_start_address_base + log_area_minimum_length;
577     u32 size;
578
579     if (entry_count)
580         *entry_count = 0;
581
582     if (!log_area_start_address_base)
583         return NULL;
584
585     while (log_area_start_address_base < end) {
586         pcpes = (struct pcpes *)log_area_start_address_base;
587         if (!is_valid_pcpes(pcpes))
588             break;
589         if (entry_count)
590             (*entry_count)++;
591         size = pcpes->eventdatasize + offsetof(struct pcpes, event);
592         log_area_start_address_last = log_area_start_address_base;
593         log_area_start_address_base += size;
594     }
595
596     if (log_area_start_address_next)
597         *log_area_start_address_next = log_area_start_address_base;
598
599     return log_area_start_address_last;
600 }
601
602
603 static u32
604 tpm_sha1_calc(const u8 *data, u32 length, u8 *hash)
605 {
606     u32 rc;
607     u32 returnCode;
608     struct tpm_res_sha1start start;
609     struct tpm_res_sha1complete complete;
610     u32 blocks = length / 64;
611     u32 rest = length & 0x3f;
612     u32 numbytes, numbytes_no;
613     u32 offset = 0;
614
615     rc = build_and_send_cmd(0, TPM_ORD_SHA1Start,
616                             NULL, 0,
617                             (u8 *)&start, sizeof(start),
618                             &returnCode, TPM_DURATION_TYPE_SHORT);
619
620     if (rc || returnCode)
621         goto err_exit;
622
623     while (blocks > 0) {
624
625         numbytes = be32_to_cpu(start.max_num_bytes);
626         if (numbytes > blocks * 64)
627              numbytes = blocks * 64;
628
629         numbytes_no = cpu_to_be32(numbytes);
630
631         rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Update,
632                                    (u8 *)&numbytes_no, sizeof(numbytes_no),
633                                    NULL, 0, &returnCode,
634                                    &data[offset], numbytes,
635                                    TPM_DURATION_TYPE_SHORT);
636
637         if (rc || returnCode)
638             goto err_exit;
639
640         offset += numbytes;
641         blocks -= (numbytes / 64);
642     }
643
644     numbytes_no = cpu_to_be32(rest);
645
646     rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Complete,
647                               (u8 *)&numbytes_no, sizeof(numbytes_no),
648                               (u8 *)&complete, sizeof(complete),
649                               &returnCode,
650                               &data[offset], rest, TPM_DURATION_TYPE_SHORT);
651
652     if (rc || returnCode)
653         goto err_exit;
654
655     memcpy(hash, complete.hash, sizeof(complete.hash));
656
657     return 0;
658
659 err_exit:
660     dprintf(DEBUG_tcg, "TCGBIOS: TPM SHA1 malfunctioning.\n");
661
662     tpm_state.tpm_working = 0;
663     if (rc)
664         return rc;
665     return TCG_TCG_COMMAND_ERROR;
666 }
667
668
669 static u32
670 sha1_calc(const u8 *data, u32 length, u8 *hash)
671 {
672     if (length < tpm_drivers[tpm_state.tpm_driver_to_use].sha1threshold)
673         return tpm_sha1_calc(data, length, hash);
674
675     return sha1(data, length, hash);
676 }
677
678
679 /*
680  * Extend the ACPI log with the given entry by copying the
681  * entry data into the log.
682  * Input
683  *  Pointer to the structure to be copied into the log
684  *
685  * Output:
686  *  lower 16 bits of return code contain entry number
687  *  if entry number is '0', then upper 16 bits contain error code.
688  */
689 static u32
690 tpm_extend_acpi_log(void *entry_ptr, u16 *entry_count)
691 {
692     u32 log_area_minimum_length, size;
693     u8 *log_area_start_address_base =
694         get_lasa_base_ptr(&log_area_minimum_length);
695     u8 *log_area_start_address_next = NULL;
696     struct pcpes *pcpes = (struct pcpes *)entry_ptr;
697
698     get_lasa_last_ptr(entry_count, &log_area_start_address_next);
699
700     dprintf(DEBUG_tcg, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n",
701             log_area_start_address_base, log_area_start_address_next);
702
703     if (log_area_start_address_next == NULL || log_area_minimum_length == 0)
704         return TCG_PC_LOGOVERFLOW;
705
706     size = pcpes->eventdatasize + offsetof(struct pcpes, event);
707
708     if ((log_area_start_address_next + size - log_area_start_address_base) >
709         log_area_minimum_length) {
710         dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
711         return TCG_PC_LOGOVERFLOW;
712     }
713
714     memcpy(log_area_start_address_next, entry_ptr, size);
715
716     (*entry_count)++;
717
718     return 0;
719 }
720
721
722 static u32
723 is_preboot_if_shutdown(void)
724 {
725     return tpm_state.if_shutdown;
726 }
727
728
729 static u32
730 shutdown_preboot_interface(void)
731 {
732     u32 rc = 0;
733
734     if (!is_preboot_if_shutdown()) {
735         tpm_state.if_shutdown = 1;
736     } else {
737         rc = TCG_INTERFACE_SHUTDOWN;
738     }
739
740     return rc;
741 }
742
743
744 static void
745 tpm_shutdown(void)
746 {
747     reset_acpi_log();
748     shutdown_preboot_interface();
749 }
750
751
752 static u32
753 pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
754 {
755     u32 rc = 0;
756     u32 resbuflen = 0;
757     struct tpm_req_header *trh;
758     u8 locty = 0;
759     struct iovec iovec[2];
760     const u32 *tmp;
761
762     if (is_preboot_if_shutdown()) {
763         rc = TCG_INTERFACE_SHUTDOWN;
764         goto err_exit;
765     }
766
767     trh = (struct tpm_req_header *)pttti->tpmopin;
768
769     if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
770         pttti->opblength < sizeof(struct pttto) ||
771         be32_to_cpu(trh->totlen)  + sizeof(struct pttti) > pttti->ipblength ) {
772         rc = TCG_INVALID_INPUT_PARA;
773         goto err_exit;
774     }
775
776     resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
777
778     iovec[0].data   = pttti->tpmopin;
779     tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
780     iovec[0].length = cpu_to_be32(*tmp);
781
782     iovec[1].data   = NULL;
783     iovec[1].length = 0;
784
785     rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen,
786                   TPM_DURATION_TYPE_LONG /* worst case */);
787     if (rc)
788         goto err_exit;
789
790     pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
791     pttto->reserved  = 0;
792
793 err_exit:
794     if (rc != 0) {
795         pttto->opblength = 4;
796         pttto->reserved = 0;
797     }
798
799     return rc;
800 }
801
802
803 static u32
804 tpm_extend(u8 *hash, u32 pcrindex)
805 {
806     u32 rc;
807     struct pttto_extend pttto;
808     struct pttti_extend pttti = {
809         .pttti = {
810             .ipblength = sizeof(struct pttti_extend),
811             .opblength = sizeof(struct pttto_extend),
812         },
813         .req = {
814             .tag      = cpu_to_be16(0xc1),
815             .totlen   = cpu_to_be32(sizeof(pttti.req)),
816             .ordinal  = cpu_to_be32(TPM_ORD_Extend),
817             .pcrindex = cpu_to_be32(pcrindex),
818         },
819     };
820
821     memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
822
823     rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
824
825     if (rc == 0) {
826         if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE ||
827             pttto.pttto.opblength !=
828                 sizeof(struct pttto) + be32_to_cpu(pttto.rsp.totlen) ||
829             be16_to_cpu(pttto.rsp.tag) != 0xc4) {
830             rc = TCG_FATAL_COM_ERROR;
831         }
832     }
833
834     if (rc)
835         tpm_shutdown();
836
837     return rc;
838 }
839
840
841 static u32
842 hash_all(const struct hai *hai, u8 *hash)
843 {
844     if (is_preboot_if_shutdown() != 0)
845         return TCG_INTERFACE_SHUTDOWN;
846
847     if (hai->ipblength != sizeof(struct hai) ||
848         hai->hashdataptr == 0 ||
849         hai->hashdatalen == 0 ||
850         hai->algorithmid != TPM_ALG_SHA)
851         return TCG_INVALID_INPUT_PARA;
852
853     return sha1_calc((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
854 }
855
856
857 static u32
858 hash_log_event(const struct hlei *hlei, struct hleo *hleo)
859 {
860     u32 rc = 0;
861     u16 size;
862     struct pcpes *pcpes;
863     u16 entry_count;
864
865     if (is_preboot_if_shutdown() != 0) {
866         rc = TCG_INTERFACE_SHUTDOWN;
867         goto err_exit;
868     }
869
870     size = hlei->ipblength;
871     if (size != sizeof(*hlei)) {
872         rc = TCG_INVALID_INPUT_PARA;
873         goto err_exit;
874     }
875
876     pcpes = (struct pcpes *)hlei->logdataptr;
877
878     if (pcpes->pcrindex >= 24 ||
879         pcpes->pcrindex  != hlei->pcrindex ||
880         pcpes->eventtype != hlei->logeventtype) {
881         rc = TCG_INVALID_INPUT_PARA;
882         goto err_exit;
883     }
884
885     if ((hlei->hashdataptr != 0) && (hlei->hashdatalen != 0)) {
886         rc = sha1_calc((const u8 *)hlei->hashdataptr,
887                        hlei->hashdatalen, pcpes->digest);
888         if (rc)
889             return rc;
890     }
891
892     rc = tpm_extend_acpi_log((void *)hlei->logdataptr, &entry_count);
893     if (rc)
894         goto err_exit;
895
896     /* updating the log was fine */
897     hleo->opblength = sizeof(struct hleo);
898     hleo->reserved  = 0;
899     hleo->eventnumber = entry_count;
900
901 err_exit:
902     if (rc != 0) {
903         hleo->opblength = 2;
904         hleo->reserved = 0;
905     }
906
907     return rc;
908 }
909
910
911 static u32
912 hash_log_extend_event(const struct hleei_short *hleei_s, struct hleeo *hleeo)
913 {
914     u32 rc = 0;
915     struct hleo hleo;
916     struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
917     const void *logdataptr;
918     u32 logdatalen;
919     struct pcpes *pcpes;
920
921     /* short or long version? */
922     switch (hleei_s->ipblength) {
923     case sizeof(struct hleei_short):
924         /* short */
925         logdataptr = hleei_s->logdataptr;
926         logdatalen = hleei_s->logdatalen;
927     break;
928
929     case sizeof(struct hleei_long):
930         /* long */
931         logdataptr = hleei_l->logdataptr;
932         logdatalen = hleei_l->logdatalen;
933     break;
934
935     default:
936         /* bad input block */
937         rc = TCG_INVALID_INPUT_PARA;
938         goto err_exit;
939     }
940
941     pcpes = (struct pcpes *)logdataptr;
942
943     struct hlei hlei = {
944         .ipblength   = sizeof(hlei),
945         .hashdataptr = hleei_s->hashdataptr,
946         .hashdatalen = hleei_s->hashdatalen,
947         .pcrindex    = hleei_s->pcrindex,
948         .logeventtype= pcpes->eventtype,
949         .logdataptr  = logdataptr,
950         .logdatalen  = logdatalen,
951     };
952
953     rc = hash_log_event(&hlei, &hleo);
954     if (rc)
955         goto err_exit;
956
957     hleeo->opblength = sizeof(struct hleeo);
958     hleeo->reserved  = 0;
959     hleeo->eventnumber = hleo.eventnumber;
960
961     rc = tpm_extend(pcpes->digest, hleei_s->pcrindex);
962
963 err_exit:
964     if (rc != 0) {
965         hleeo->opblength = 4;
966         hleeo->reserved  = 0;
967     }
968
969     return rc;
970
971 }
972
973
974 static u32
975 tss(struct ti *ti, struct to *to)
976 {
977     u32 rc = 0;
978
979     if (is_preboot_if_shutdown() == 0) {
980         rc = TCG_PC_UNSUPPORTED;
981     } else {
982         rc = TCG_INTERFACE_SHUTDOWN;
983     }
984
985     to->opblength = sizeof(struct to);
986     to->reserved  = 0;
987
988     return rc;
989 }
990
991
992 static u32
993 compact_hash_log_extend_event(u8 *buffer,
994                               u32 info,
995                               u32 length,
996                               u32 pcrindex,
997                               u32 *edx_ptr)
998 {
999     u32 rc = 0;
1000     struct hleeo hleeo;
1001     struct pcpes pcpes = {
1002         .pcrindex      = pcrindex,
1003         .eventtype     = EV_COMPACT_HASH,
1004         .eventdatasize = sizeof(info),
1005         .event         = info,
1006     };
1007     struct hleei_short hleei = {
1008         .ipblength   = sizeof(hleei),
1009         .hashdataptr = buffer,
1010         .hashdatalen = length,
1011         .pcrindex    = pcrindex,
1012         .logdataptr  = &pcpes,
1013         .logdatalen  = sizeof(pcpes),
1014     };
1015
1016     rc = hash_log_extend_event(&hleei, &hleeo);
1017     if (rc == 0)
1018         *edx_ptr = hleeo.eventnumber;
1019
1020     return rc;
1021 }
1022
1023
1024 void VISIBLE32FLAT
1025 tpm_interrupt_handler32(struct bregs *regs)
1026 {
1027     if (!CONFIG_TCGBIOS)
1028         return;
1029
1030     set_cf(regs, 0);
1031
1032     if (!has_working_tpm()) {
1033         regs->eax = TCG_GENERAL_ERROR;
1034         return;
1035     }
1036
1037     switch ((enum irq_ids)regs->al) {
1038     case TCG_StatusCheck:
1039         if (is_tpm_present() == 0) {
1040             /* no TPM available */
1041             regs->eax = TCG_PC_TPM_NOT_PRESENT;
1042         } else {
1043             regs->eax = 0;
1044             regs->ebx = TCG_MAGIC;
1045             regs->ch = TCG_VERSION_MAJOR;
1046             regs->cl = TCG_VERSION_MINOR;
1047             regs->edx = 0x0;
1048             regs->esi = (u32)get_lasa_base_ptr(NULL);
1049             regs->edi =
1050                   (u32)get_lasa_last_ptr(NULL, NULL);
1051         }
1052         break;
1053
1054     case TCG_HashLogExtendEvent:
1055         regs->eax =
1056             hash_log_extend_event(
1057                   (struct hleei_short *)input_buf32(regs),
1058                   (struct hleeo *)output_buf32(regs));
1059         break;
1060
1061     case TCG_PassThroughToTPM:
1062         regs->eax =
1063             pass_through_to_tpm((struct pttti *)input_buf32(regs),
1064                                 (struct pttto *)output_buf32(regs));
1065         break;
1066
1067     case TCG_ShutdownPreBootInterface:
1068         regs->eax = shutdown_preboot_interface();
1069         break;
1070
1071     case TCG_HashLogEvent:
1072         regs->eax = hash_log_event((struct hlei*)input_buf32(regs),
1073                                    (struct hleo*)output_buf32(regs));
1074         break;
1075
1076     case TCG_HashAll:
1077         regs->eax =
1078             hash_all((struct hai*)input_buf32(regs),
1079                      (u8 *)output_buf32(regs));
1080         break;
1081
1082     case TCG_TSS:
1083         regs->eax = tss((struct ti*)input_buf32(regs),
1084                     (struct to*)output_buf32(regs));
1085         break;
1086
1087     case TCG_CompactHashLogExtendEvent:
1088         regs->eax =
1089           compact_hash_log_extend_event((u8 *)input_buf32(regs),
1090                                         regs->esi,
1091                                         regs->ecx,
1092                                         regs->edx,
1093                                         &regs->edx);
1094         break;
1095
1096     default:
1097         set_cf(regs, 1);
1098     }
1099
1100     return;
1101 }
1102
1103 /*
1104  * Add a measurement to the log; the data at data_seg:data/length are
1105  * appended to the TCG_PCClientPCREventStruct
1106  *
1107  * Input parameters:
1108  *  pcrIndex   : which PCR to extend
1109  *  event_type : type of event; specs section on 'Event Types'
1110  *  info       : pointer to info (e.g., string) to be added to log as-is
1111  *  info_length: length of the info
1112  *  data       : pointer to the data (i.e., string) to be added to the log
1113  *  data_length: length of the data
1114  */
1115 static u32
1116 tpm_add_measurement_to_log(u32 pcrIndex, u32 event_type,
1117                            const char *info, u32 info_length,
1118                            const u8 *data, u32 data_length)
1119 {
1120     u32 rc = 0;
1121     struct hleeo hleeo;
1122     u8 _pcpes[offsetof(struct pcpes, event) + 400];
1123     struct pcpes *pcpes = (struct pcpes *)_pcpes;
1124
1125     if (info_length < sizeof(_pcpes) - offsetof(struct pcpes, event)) {
1126
1127         pcpes->pcrindex      = pcrIndex;
1128         pcpes->eventtype     = event_type;
1129         memset(&pcpes->digest, 0x0, sizeof(pcpes->digest));
1130         pcpes->eventdatasize = info_length;
1131         memcpy(&pcpes->event, info, info_length);
1132
1133         struct hleei_short hleei = {
1134             .ipblength   = sizeof(hleei),
1135             .hashdataptr = data,
1136             .hashdatalen = data_length,
1137             .pcrindex    = pcrIndex,
1138             .logdataptr  = _pcpes,
1139             .logdatalen  = info_length + offsetof(struct pcpes, event),
1140         };
1141
1142         rc = hash_log_extend_event(&hleei, &hleeo);
1143     } else {
1144         rc = TCG_GENERAL_ERROR;
1145     }
1146
1147     return rc;
1148 }
1149
1150
1151 /*
1152  * Add a measurement to the list of measurements
1153  * pcrIndex   : PCR to be extended
1154  * event_type : type of event; specs section on 'Event Types'
1155  * data       : additional parameter; used as parameter for
1156  *              'action index'
1157  */
1158 static u32
1159 tpm_add_measurement(u32 pcrIndex,
1160                     u16 event_type,
1161                     const char *string)
1162 {
1163     u32 rc;
1164     u32 len;
1165
1166     switch (event_type) {
1167     case EV_SEPARATOR:
1168         len = sizeof(evt_separator);
1169         rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1170                                         (char *)NULL, 0,
1171                                         (u8 *)evt_separator, len);
1172         break;
1173
1174     case EV_ACTION:
1175         rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1176                                         string, strlen(string),
1177                                         (u8 *)string, strlen(string));
1178         break;
1179
1180     default:
1181         rc = TCG_INVALID_INPUT_PARA;
1182     }
1183
1184     return rc;
1185 }
1186
1187
1188 static u32
1189 tpm_calling_int19h(void)
1190 {
1191     if (!CONFIG_TCGBIOS)
1192         return 0;
1193
1194     if (!has_working_tpm())
1195         return TCG_GENERAL_ERROR;
1196
1197     return tpm_add_measurement(4, EV_ACTION,
1198                                "Calling INT 19h");
1199 }
1200
1201 /*
1202  * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
1203  */
1204 u32
1205 tpm_add_event_separators(void)
1206 {
1207     u32 rc;
1208     u32 pcrIndex = 0;
1209
1210     if (!CONFIG_TCGBIOS)
1211         return 0;
1212
1213     if (!has_working_tpm())
1214         return TCG_GENERAL_ERROR;
1215
1216     while (pcrIndex <= 7) {
1217         rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
1218         if (rc)
1219             break;
1220         pcrIndex ++;
1221     }
1222
1223     return rc;
1224 }
1225
1226
1227 /*
1228  * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
1229  * the list of measurements.
1230  */
1231 static u32
1232 tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
1233 {
1234     const char *string;
1235
1236     if (!CONFIG_TCGBIOS)
1237         return 0;
1238
1239     if (!has_working_tpm())
1240         return TCG_GENERAL_ERROR;
1241
1242     switch (bootcd) {
1243     case 0:
1244         switch (bootdrv) {
1245         case 0:
1246             string = "Booting BCV device 00h (Floppy)";
1247             break;
1248
1249         case 0x80:
1250             string = "Booting BCV device 80h (HDD)";
1251             break;
1252
1253         default:
1254             string = "Booting unknown device";
1255             break;
1256         }
1257
1258         break;
1259
1260     default:
1261         string = "Booting from CD ROM device";
1262     }
1263
1264     return tpm_add_measurement_to_log(4, EV_ACTION,
1265                                       string, strlen(string),
1266                                       (u8 *)string, strlen(string));
1267 }
1268
1269
1270 /*
1271  * Add measurement to the log about option rom scan
1272  */
1273 u32
1274 tpm_start_option_rom_scan(void)
1275 {
1276     if (!CONFIG_TCGBIOS)
1277         return 0;
1278
1279     if (!has_working_tpm())
1280         return TCG_GENERAL_ERROR;
1281
1282     return tpm_add_measurement(2, EV_ACTION,
1283                                "Start Option ROM Scan");
1284 }
1285
1286
1287 /*
1288  * Add measurement to the log about an option rom
1289  */
1290 u32
1291 tpm_option_rom(const void *addr, u32 len)
1292 {
1293     if (!CONFIG_TCGBIOS)
1294         return 0;
1295
1296     if (!has_working_tpm())
1297         return TCG_GENERAL_ERROR;
1298
1299     u32 rc;
1300     struct pcctes_romex pcctes = {
1301         .eventid = 7,
1302         .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
1303     };
1304
1305     rc = sha1((const u8 *)addr, len, pcctes.digest);
1306     if (rc)
1307         return rc;
1308
1309     return tpm_add_measurement_to_log(2,
1310                                       EV_EVENT_TAG,
1311                                       (const char *)&pcctes, sizeof(pcctes),
1312                                       (u8 *)&pcctes, sizeof(pcctes));
1313 }
1314
1315
1316 u32
1317 tpm_smbios_measure(void)
1318 {
1319     if (!CONFIG_TCGBIOS)
1320         return 0;
1321
1322     if (!has_working_tpm())
1323         return TCG_GENERAL_ERROR;
1324
1325     u32 rc;
1326     struct pcctes pcctes = {
1327         .eventid = 1,
1328         .eventdatasize = SHA1_BUFSIZE,
1329     };
1330     struct smbios_entry_point *sep = SMBiosAddr;
1331
1332     dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
1333
1334     if (!sep)
1335         return 0;
1336
1337     rc = sha1((const u8 *)sep->structure_table_address,
1338               sep->structure_table_length, pcctes.digest);
1339     if (rc)
1340         return rc;
1341
1342     return tpm_add_measurement_to_log(1,
1343                                       EV_EVENT_TAG,
1344                                       (const char *)&pcctes, sizeof(pcctes),
1345                                       (u8 *)&pcctes, sizeof(pcctes));
1346 }
1347
1348
1349 /*
1350  * Add a measurement related to Initial Program Loader to the log.
1351  * Creates two log entries.
1352  *
1353  * Input parameter:
1354  *  bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
1355  *  addr   : address where the IP data are located
1356  *  length : IP data length in bytes
1357  */
1358 static u32
1359 tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
1360 {
1361     u32 rc;
1362     const char *string;
1363
1364     switch (bootcd) {
1365     case IPL_EL_TORITO_1:
1366         /* specs: see section 'El Torito' */
1367         string = "EL TORITO IPL";
1368         rc = tpm_add_measurement_to_log(4, EV_IPL,
1369                                         string, strlen(string),
1370                                         addr, length);
1371         break;
1372
1373     case IPL_EL_TORITO_2:
1374         /* specs: see section 'El Torito' */
1375         string = "BOOT CATALOG";
1376         rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1377                                         string, strlen(string),
1378                                         addr, length);
1379         break;
1380
1381     default:
1382         /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1383         /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
1384         string = "MBR";
1385         rc = tpm_add_measurement_to_log(4, EV_IPL,
1386                                         string, strlen(string),
1387                                         addr, 0x1b8);
1388
1389         if (rc)
1390             break;
1391
1392         /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
1393         string = "MBR PARTITION_TABLE";
1394         rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1395                                         string, strlen(string),
1396                                         addr + 0x1b8, 0x48);
1397     }
1398
1399     return rc;
1400 }
1401
1402 u32
1403 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1404 {
1405     if (!CONFIG_TCGBIOS)
1406         return 0;
1407
1408     if (!has_working_tpm())
1409         return TCG_GENERAL_ERROR;
1410
1411     u32 rc = tpm_add_bootdevice(0, bootdrv);
1412     if (rc)
1413         return rc;
1414
1415     return tpm_ipl(IPL_BCV, addr, length);
1416 }
1417
1418 u32
1419 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1420 {
1421     if (!CONFIG_TCGBIOS)
1422         return 0;
1423
1424     if (!has_working_tpm())
1425         return TCG_GENERAL_ERROR;
1426
1427     u32 rc = tpm_add_bootdevice(1, bootdrv);
1428     if (rc)
1429         return rc;
1430
1431     return tpm_ipl(IPL_EL_TORITO_1, addr, length);
1432 }
1433
1434 u32
1435 tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1436 {
1437     if (!CONFIG_TCGBIOS)
1438         return 0;
1439
1440     if (!has_working_tpm())
1441         return TCG_GENERAL_ERROR;
1442
1443     u32 rc = tpm_add_bootdevice(1, 0);
1444     if (rc)
1445         return rc;
1446
1447     return tpm_ipl(IPL_EL_TORITO_2, addr, length);
1448 }
1449
1450 void
1451 tpm_s3_resume(void)
1452 {
1453     u32 rc;
1454     u32 returnCode;
1455
1456     if (!CONFIG_TCGBIOS)
1457         return;
1458
1459     if (!has_working_tpm())
1460         return;
1461
1462     dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1463
1464     rc = build_and_send_cmd(0, TPM_ORD_Startup,
1465                             Startup_ST_STATE, sizeof(Startup_ST_STATE),
1466                             NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
1467
1468     dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
1469             returnCode);
1470
1471     if (rc || returnCode)
1472         goto err_exit;
1473
1474     return;
1475
1476 err_exit:
1477     dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1478
1479     tpm_state.tpm_working = 0;
1480 }