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
5 // Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
8 // Stefan Berger <stefanb@linux.vnet.ibm.com>
10 // This file may be distributed under the terms of the GNU LGPLv3 license.
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"
29 static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
30 static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
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 };
37 static const u8 CommandFlag_FALSE[1] = { 0x00 };
38 static const u8 CommandFlag_TRUE[1] = { 0x01 };
40 static const u8 GetCapability_Permanent_Flags[] = {
41 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
42 0x00, 0x00, 0x01, 0x08
45 static const u8 GetCapability_OwnerAuth[] = {
46 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
47 0x00, 0x00, 0x01, 0x11
50 static const u8 GetCapability_Timeouts[] = {
51 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
52 0x00, 0x00, 0x01, 0x15
55 static const u8 GetCapability_Durations[] = {
56 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
57 0x00, 0x00, 0x01, 0x20
60 static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
63 #define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr)
65 /* local function prototypes */
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);
72 /* helper functions */
74 static inline void *input_buf32(struct bregs *regs)
76 return MAKE_FLATPTR(regs->es, regs->di);
79 static inline void *output_buf32(struct bregs *regs)
81 return MAKE_FLATPTR(regs->ds, regs->si);
90 u8 tpm_driver_to_use:4;
94 static tpm_state_t tpm_state = {
95 .tpm_driver_to_use = TPM_INVALID_DRIVER,
99 /********************************************************
100 Extensions for TCG-enabled BIOS
101 *******************************************************/
110 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
111 struct tpm_driver *td = &tpm_drivers[i];
112 if (td->probe() != 0) {
114 tpm_state.tpm_driver_to_use = i;
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;
134 has_working_tpm(void)
138 return tpm_state.tpm_working;
141 static struct tcpa_descriptor_rev2 *
142 find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
145 struct tcpa_descriptor_rev2 *tcpa = NULL;
146 struct rsdt_descriptor *rsdt;
150 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
154 length = rsdt->length;
155 off = offsetof(struct rsdt_descriptor, entry);
157 while ((off + sizeof(rsdt->entry[0])) <= length) {
158 /* try all pointers to structures */
159 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
161 /* valid TCPA ACPI table ? */
162 if (tcpa->signature == TCPA_SIGNATURE &&
163 checksum((u8 *)tcpa, tcpa->length) == 0)
167 off += sizeof(rsdt->entry[0]);
175 static struct tcpa_descriptor_rev2 *
176 find_tcpa_table(void)
178 struct tcpa_descriptor_rev2 *tcpa = NULL;
179 struct rsdp_descriptor *rsdp = RsdpAddr;
182 tcpa = find_tcpa_by_rsdp(rsdp);
184 tpm_state.if_shutdown = 1;
188 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
190 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
197 get_lasa_base_ptr(u32 *log_area_minimum_length)
199 u8 *log_area_start_address = 0;
200 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
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;
208 return log_area_start_address;
212 /* clear the ACPI log */
216 u32 log_area_minimum_length;
217 u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
219 if (log_area_start_address)
220 memset(log_area_start_address, 0x0, log_area_minimum_length);
225 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
226 where the TCPA table is.
231 tpm_state.if_shutdown = 0;
232 tpm_state.tpm_probed = 0;
233 tpm_state.tpm_found = 0;
234 tpm_state.tpm_working = 0;
236 if (!has_working_tpm()) {
237 tpm_state.if_shutdown = 1;
246 transmit(u8 locty, const struct iovec iovec[],
247 u8 *respbuffer, u32 *respbufferlen,
248 enum tpmDurationType to_t)
252 struct tpm_driver *td;
255 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
256 return TCG_FATAL_COM_ERROR;
258 td = &tpm_drivers[tpm_state.tpm_driver_to_use];
260 irc = td->activate(locty);
262 /* tpm could not be activated */
263 return TCG_FATAL_COM_ERROR;
266 for (i = 0; iovec[i].length; i++) {
267 irc = td->senddata(iovec[i].data,
270 return TCG_FATAL_COM_ERROR;
273 irc = td->waitdatavalid();
275 return TCG_FATAL_COM_ERROR;
277 irc = td->waitrespready(to_t);
279 return TCG_FATAL_COM_ERROR;
281 irc = td->readresp(respbuffer,
284 return TCG_FATAL_COM_ERROR;
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.
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)
304 #define MAX_APPEND_SIZE sizeof(GetCapability_Timeouts)
305 #define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags)
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);
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;
321 iovec[0].data = trqh;
322 iovec[0].length = TPM_REQ_HEADER_SIZE + append_size;
325 iovec[1].data = (void *)otherdata;
326 iovec[1].length = otherdata_size;
330 iovec[idx].data = NULL;
331 iovec[idx].length = 0;
333 memset(ibuffer, 0x0, sizeof(ibuffer));
334 memset(obuffer, 0x0, sizeof(obuffer));
336 trqh->tag = cpu_to_be16(TPM_TAG_RQU_CMD);
337 trqh->totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size +
339 trqh->ordinal = cpu_to_be32(ordinal);
342 memcpy((char *)trqh + sizeof(*trqh),
343 append, append_size);
345 rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
349 *returnCode = be32_to_cpu(trsh->errcode);
352 memcpy(resbuffer, trsh, return_size);
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)
363 return build_and_send_cmd_od(locty, ordinal, append, append_size,
364 resbuffer, return_size, returnCode,
370 determine_timeouts(void)
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];
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);
385 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
386 " = 0x%08x\n", returnCode);
388 if (rc || returnCode)
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);
397 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
398 " = 0x%08x\n", returnCode);
400 if (rc || returnCode)
403 for (i = 0; i < 3; i++)
404 durations.durations[i] = be32_to_cpu(durations.durations[i]);
406 for (i = 0; i < 4; i++)
407 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
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]);
415 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
416 durations.durations[0],
417 durations.durations[1],
418 durations.durations[2]);
421 td->set_timeouts(timeouts.timeouts, durations.durations);
426 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
428 tpm_state.tpm_working = 0;
431 return TCG_TCG_COMMAND_ERROR;
441 if (!has_working_tpm())
442 return TCG_GENERAL_ERROR;
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);
449 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
452 if (CONFIG_COREBOOT) {
453 /* with other firmware on the system the TPM may already have been
456 if (returnCode == TPM_INVALID_POSTINIT)
460 if (rc || returnCode)
463 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
464 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
466 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
469 if (rc || returnCode)
472 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
473 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
475 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
478 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
481 rc = determine_timeouts();
485 rc = tpm_smbios_measure();
489 rc = tpm_start_option_rom_scan();
496 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
498 tpm_state.tpm_working = 0;
501 return TCG_TCG_COMMAND_ERROR;
528 if (!has_working_tpm())
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)
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)
545 rc = tpm_calling_int19h();
549 rc = tpm_add_event_separators();
556 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
558 tpm_state.tpm_working = 0;
562 is_valid_pcpes(struct pcpes *pcpes)
564 return (pcpes->eventtype != 0);
569 get_lasa_last_ptr(u16 *entry_count, u8 **log_area_start_address_next)
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;
582 if (!log_area_start_address_base)
585 while (log_area_start_address_base < end) {
586 pcpes = (struct pcpes *)log_area_start_address_base;
587 if (!is_valid_pcpes(pcpes))
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;
596 if (log_area_start_address_next)
597 *log_area_start_address_next = log_area_start_address_base;
599 return log_area_start_address_last;
604 tpm_sha1_calc(const u8 *data, u32 length, u8 *hash)
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;
615 rc = build_and_send_cmd(0, TPM_ORD_SHA1Start,
617 (u8 *)&start, sizeof(start),
618 &returnCode, TPM_DURATION_TYPE_SHORT);
620 if (rc || returnCode)
625 numbytes = be32_to_cpu(start.max_num_bytes);
626 if (numbytes > blocks * 64)
627 numbytes = blocks * 64;
629 numbytes_no = cpu_to_be32(numbytes);
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);
637 if (rc || returnCode)
641 blocks -= (numbytes / 64);
644 numbytes_no = cpu_to_be32(rest);
646 rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Complete,
647 (u8 *)&numbytes_no, sizeof(numbytes_no),
648 (u8 *)&complete, sizeof(complete),
650 &data[offset], rest, TPM_DURATION_TYPE_SHORT);
652 if (rc || returnCode)
655 memcpy(hash, complete.hash, sizeof(complete.hash));
660 dprintf(DEBUG_tcg, "TCGBIOS: TPM SHA1 malfunctioning.\n");
662 tpm_state.tpm_working = 0;
665 return TCG_TCG_COMMAND_ERROR;
670 sha1_calc(const u8 *data, u32 length, u8 *hash)
672 if (length < tpm_drivers[tpm_state.tpm_driver_to_use].sha1threshold)
673 return tpm_sha1_calc(data, length, hash);
675 return sha1(data, length, hash);
680 * Extend the ACPI log with the given entry by copying the
681 * entry data into the log.
683 * Pointer to the structure to be copied into the log
686 * lower 16 bits of return code contain entry number
687 * if entry number is '0', then upper 16 bits contain error code.
690 tpm_extend_acpi_log(void *entry_ptr, u16 *entry_count)
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;
698 get_lasa_last_ptr(entry_count, &log_area_start_address_next);
700 dprintf(DEBUG_tcg, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n",
701 log_area_start_address_base, log_area_start_address_next);
703 if (log_area_start_address_next == NULL || log_area_minimum_length == 0)
704 return TCG_PC_LOGOVERFLOW;
706 size = pcpes->eventdatasize + offsetof(struct pcpes, event);
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;
714 memcpy(log_area_start_address_next, entry_ptr, size);
723 is_preboot_if_shutdown(void)
725 return tpm_state.if_shutdown;
730 shutdown_preboot_interface(void)
734 if (!is_preboot_if_shutdown()) {
735 tpm_state.if_shutdown = 1;
737 rc = TCG_INTERFACE_SHUTDOWN;
748 shutdown_preboot_interface();
753 pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
757 struct tpm_req_header *trh;
759 struct iovec iovec[2];
762 if (is_preboot_if_shutdown()) {
763 rc = TCG_INTERFACE_SHUTDOWN;
767 trh = (struct tpm_req_header *)pttti->tpmopin;
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;
776 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
778 iovec[0].data = pttti->tpmopin;
779 tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
780 iovec[0].length = cpu_to_be32(*tmp);
782 iovec[1].data = NULL;
785 rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen,
786 TPM_DURATION_TYPE_LONG /* worst case */);
790 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
795 pttto->opblength = 4;
804 tpm_extend(u8 *hash, u32 pcrindex)
807 struct pttto_extend pttto;
808 struct pttti_extend pttti = {
810 .ipblength = sizeof(struct pttti_extend),
811 .opblength = sizeof(struct pttto_extend),
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),
821 memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
823 rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
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;
842 hash_all(const struct hai *hai, u8 *hash)
844 if (is_preboot_if_shutdown() != 0)
845 return TCG_INTERFACE_SHUTDOWN;
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;
853 return sha1_calc((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
858 hash_log_event(const struct hlei *hlei, struct hleo *hleo)
865 if (is_preboot_if_shutdown() != 0) {
866 rc = TCG_INTERFACE_SHUTDOWN;
870 size = hlei->ipblength;
871 if (size != sizeof(*hlei)) {
872 rc = TCG_INVALID_INPUT_PARA;
876 pcpes = (struct pcpes *)hlei->logdataptr;
878 if (pcpes->pcrindex >= 24 ||
879 pcpes->pcrindex != hlei->pcrindex ||
880 pcpes->eventtype != hlei->logeventtype) {
881 rc = TCG_INVALID_INPUT_PARA;
885 if ((hlei->hashdataptr != 0) && (hlei->hashdatalen != 0)) {
886 rc = sha1_calc((const u8 *)hlei->hashdataptr,
887 hlei->hashdatalen, pcpes->digest);
892 rc = tpm_extend_acpi_log((void *)hlei->logdataptr, &entry_count);
896 /* updating the log was fine */
897 hleo->opblength = sizeof(struct hleo);
899 hleo->eventnumber = entry_count;
912 hash_log_extend_event(const struct hleei_short *hleei_s, struct hleeo *hleeo)
916 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
917 const void *logdataptr;
921 /* short or long version? */
922 switch (hleei_s->ipblength) {
923 case sizeof(struct hleei_short):
925 logdataptr = hleei_s->logdataptr;
926 logdatalen = hleei_s->logdatalen;
929 case sizeof(struct hleei_long):
931 logdataptr = hleei_l->logdataptr;
932 logdatalen = hleei_l->logdatalen;
936 /* bad input block */
937 rc = TCG_INVALID_INPUT_PARA;
941 pcpes = (struct pcpes *)logdataptr;
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,
953 rc = hash_log_event(&hlei, &hleo);
957 hleeo->opblength = sizeof(struct hleeo);
959 hleeo->eventnumber = hleo.eventnumber;
961 rc = tpm_extend(pcpes->digest, hleei_s->pcrindex);
965 hleeo->opblength = 4;
975 tss(struct ti *ti, struct to *to)
979 if (is_preboot_if_shutdown() == 0) {
980 rc = TCG_PC_UNSUPPORTED;
982 rc = TCG_INTERFACE_SHUTDOWN;
985 to->opblength = sizeof(struct to);
993 compact_hash_log_extend_event(u8 *buffer,
1001 struct pcpes pcpes = {
1002 .pcrindex = pcrindex,
1003 .eventtype = EV_COMPACT_HASH,
1004 .eventdatasize = sizeof(info),
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),
1016 rc = hash_log_extend_event(&hleei, &hleeo);
1018 *edx_ptr = hleeo.eventnumber;
1025 tpm_interrupt_handler32(struct bregs *regs)
1027 if (!CONFIG_TCGBIOS)
1032 if (!has_working_tpm()) {
1033 regs->eax = TCG_GENERAL_ERROR;
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;
1044 regs->ebx = TCG_MAGIC;
1045 regs->ch = TCG_VERSION_MAJOR;
1046 regs->cl = TCG_VERSION_MINOR;
1048 regs->esi = (u32)get_lasa_base_ptr(NULL);
1050 (u32)get_lasa_last_ptr(NULL, NULL);
1054 case TCG_HashLogExtendEvent:
1056 hash_log_extend_event(
1057 (struct hleei_short *)input_buf32(regs),
1058 (struct hleeo *)output_buf32(regs));
1061 case TCG_PassThroughToTPM:
1063 pass_through_to_tpm((struct pttti *)input_buf32(regs),
1064 (struct pttto *)output_buf32(regs));
1067 case TCG_ShutdownPreBootInterface:
1068 regs->eax = shutdown_preboot_interface();
1071 case TCG_HashLogEvent:
1072 regs->eax = hash_log_event((struct hlei*)input_buf32(regs),
1073 (struct hleo*)output_buf32(regs));
1078 hash_all((struct hai*)input_buf32(regs),
1079 (u8 *)output_buf32(regs));
1083 regs->eax = tss((struct ti*)input_buf32(regs),
1084 (struct to*)output_buf32(regs));
1087 case TCG_CompactHashLogExtendEvent:
1089 compact_hash_log_extend_event((u8 *)input_buf32(regs),
1104 * Add a measurement to the log; the data at data_seg:data/length are
1105 * appended to the TCG_PCClientPCREventStruct
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
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)
1122 u8 _pcpes[offsetof(struct pcpes, event) + 400];
1123 struct pcpes *pcpes = (struct pcpes *)_pcpes;
1125 if (info_length < sizeof(_pcpes) - offsetof(struct pcpes, event)) {
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);
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),
1142 rc = hash_log_extend_event(&hleei, &hleeo);
1144 rc = TCG_GENERAL_ERROR;
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
1159 tpm_add_measurement(u32 pcrIndex,
1166 switch (event_type) {
1168 len = sizeof(evt_separator);
1169 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1171 (u8 *)evt_separator, len);
1175 rc = tpm_add_measurement_to_log(pcrIndex, event_type,
1176 string, strlen(string),
1177 (u8 *)string, strlen(string));
1181 rc = TCG_INVALID_INPUT_PARA;
1189 tpm_calling_int19h(void)
1191 if (!CONFIG_TCGBIOS)
1194 if (!has_working_tpm())
1195 return TCG_GENERAL_ERROR;
1197 return tpm_add_measurement(4, EV_ACTION,
1202 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
1205 tpm_add_event_separators(void)
1210 if (!CONFIG_TCGBIOS)
1213 if (!has_working_tpm())
1214 return TCG_GENERAL_ERROR;
1216 while (pcrIndex <= 7) {
1217 rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
1228 * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
1229 * the list of measurements.
1232 tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
1236 if (!CONFIG_TCGBIOS)
1239 if (!has_working_tpm())
1240 return TCG_GENERAL_ERROR;
1246 string = "Booting BCV device 00h (Floppy)";
1250 string = "Booting BCV device 80h (HDD)";
1254 string = "Booting unknown device";
1261 string = "Booting from CD ROM device";
1264 return tpm_add_measurement_to_log(4, EV_ACTION,
1265 string, strlen(string),
1266 (u8 *)string, strlen(string));
1271 * Add measurement to the log about option rom scan
1274 tpm_start_option_rom_scan(void)
1276 if (!CONFIG_TCGBIOS)
1279 if (!has_working_tpm())
1280 return TCG_GENERAL_ERROR;
1282 return tpm_add_measurement(2, EV_ACTION,
1283 "Start Option ROM Scan");
1288 * Add measurement to the log about an option rom
1291 tpm_option_rom(const void *addr, u32 len)
1293 if (!CONFIG_TCGBIOS)
1296 if (!has_working_tpm())
1297 return TCG_GENERAL_ERROR;
1300 struct pcctes_romex pcctes = {
1302 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
1305 rc = sha1((const u8 *)addr, len, pcctes.digest);
1309 return tpm_add_measurement_to_log(2,
1311 (const char *)&pcctes, sizeof(pcctes),
1312 (u8 *)&pcctes, sizeof(pcctes));
1317 tpm_smbios_measure(void)
1319 if (!CONFIG_TCGBIOS)
1322 if (!has_working_tpm())
1323 return TCG_GENERAL_ERROR;
1326 struct pcctes pcctes = {
1328 .eventdatasize = SHA1_BUFSIZE,
1330 struct smbios_entry_point *sep = SMBiosAddr;
1332 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
1337 rc = sha1((const u8 *)sep->structure_table_address,
1338 sep->structure_table_length, pcctes.digest);
1342 return tpm_add_measurement_to_log(1,
1344 (const char *)&pcctes, sizeof(pcctes),
1345 (u8 *)&pcctes, sizeof(pcctes));
1350 * Add a measurement related to Initial Program Loader to the log.
1351 * Creates two log entries.
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
1359 tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
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),
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),
1382 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1383 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
1385 rc = tpm_add_measurement_to_log(4, EV_IPL,
1386 string, strlen(string),
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);
1403 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1405 if (!CONFIG_TCGBIOS)
1408 if (!has_working_tpm())
1409 return TCG_GENERAL_ERROR;
1411 u32 rc = tpm_add_bootdevice(0, bootdrv);
1415 return tpm_ipl(IPL_BCV, addr, length);
1419 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1421 if (!CONFIG_TCGBIOS)
1424 if (!has_working_tpm())
1425 return TCG_GENERAL_ERROR;
1427 u32 rc = tpm_add_bootdevice(1, bootdrv);
1431 return tpm_ipl(IPL_EL_TORITO_1, addr, length);
1435 tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1437 if (!CONFIG_TCGBIOS)
1440 if (!has_working_tpm())
1441 return TCG_GENERAL_ERROR;
1443 u32 rc = tpm_add_bootdevice(1, 0);
1447 return tpm_ipl(IPL_EL_TORITO_2, addr, length);
1456 if (!CONFIG_TCGBIOS)
1459 if (!has_working_tpm())
1462 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
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);
1468 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
1471 if (rc || returnCode)
1477 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1479 tpm_state.tpm_working = 0;