This patch implements the main part of the TCG BIOS extensions. It provides the following functionality:
- initialization of the TCPA ACPI table used for logging of measurements - initialization of the TPM by sending a sequence of commands to it - proper setup of the TPM once the BIOS hands over control to the bootloader - support for S3 resume; BIOS sends TPM_Startup(ST_STATE) to TPM - a utility function called mssleep is added. It waits for a number of milliseconds before it returns. I had tried to build a function like that based on calc_future_time() and check_timer(), but those didn't work once in an S3 resume.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
--- src/boot.c | 2 src/post.c | 5 src/resume.c | 2 src/tcgbios.c | 525 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tcgbios.h | 386 ++++++++++++++++++++++++++++++++++++++++++ src/util.c | 18 + src/util.h | 5 7 files changed, 943 insertions(+)
Index: seabios/src/tcgbios.c =================================================================== --- /dev/null +++ seabios/src/tcgbios.c @@ -0,0 +1,525 @@ +/* + * Implementation of the TCG BIOS extension according to the specification + * described in + * https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementat... + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) IBM Corporation, 2006,2010,2011 + * + * Author: Stefan Berger stefanb@us.ibm.com + */ + +#include "config.h" + +#if CONFIG_TCGBIOS + +#include "types.h" +#include "tpm_drivers.h" // tpm_drivers[] +#include "util.h" // printf, get_keystroke +#include "tcgbios.h"// tcpa_*, prototypes +#include "acpi.h" // RSDP_SIGNATURE, rsdt_descriptor +#include "smbios.h" // smbios_entry_point + + +//#define DEBUG_TCGBIOS + +static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR }; +static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE }; + +static const u8 PhysicalPresence_CMD_ENABLE[2] = { 0x00, 0x20 }; +static const u8 PhysicalPresence_CMD_DISABLE[2] = { 0x01, 0x00 }; +static const u8 PhysicalPresence_PRESENT[2] = { 0x00, 0x08 }; +static const u8 PhysicalPresence_NOT_PRESENT[2] = { 0x00, 0x10 }; +static const u8 PhysicalPresence_LOCK[2] = { 0x00, 0x04 }; + +static const u8 CommandFlag_FALSE[1] = { 0x00 }; +static const u8 CommandFlag_TRUE[1] = { 0x01 }; + +static const u8 GetCapability_Permanent_Flags[12] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x08 +}; + +static const u8 GetCapability_OwnerAuth[12] = { + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x11 +}; + + +#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr) + + +/* helper functions */ + +static inline void *input_buf32(struct bregs *regs) +{ + return MAKE_FLATPTR(regs->es, regs->di); +} + +static inline void *output_buf32(struct bregs *regs) +{ + return MAKE_FLATPTR(regs->ds, regs->si); +} + + +typedef struct { + u8 tpm_probed:1; + u8 tpm_found:1; + u8 tpm_working:1; + u8 if_shutdown:1; + u8 tpm_driver_to_use:4; +} tcpa_state_t; + + +static tcpa_state_t tcpa_state = { + .tpm_driver_to_use = TPM_INVALID_DRIVER, +}; + +extern struct tpm_driver tpm_drivers[]; + + +/******************************************************** + Extensions for TCG-enabled BIOS + *******************************************************/ + + +static u32 +is_tpm_present(void) +{ + u32 rc = 0; + unsigned int i; + + for (i = 0; i < TPM_NUM_DRIVERS; i++) { + struct tpm_driver *td = &tpm_drivers[i]; + if (td->probe() != 0) { + td->init(); + tcpa_state.tpm_driver_to_use = i; + rc = 1; + break; + } + } + + return rc; +} + + +int +has_working_tpm(void) +{ + if (!tcpa_state.tpm_probed) { + tcpa_state.tpm_probed = 1; + tcpa_state.tpm_found = (is_tpm_present() != 0); + tcpa_state.tpm_working = 1; + } + if (!tcpa_state.tpm_working) + return 0; + + return tcpa_state.tpm_found; +} + + +static u8 +calc_checksum(const u8 *addr, u32 length) +{ + u8 sum = 0; + u32 ctr; + + for (ctr = 0; ctr < length; ctr++) + sum += addr[ctr]; + + return sum; +} + + +/* + * Search for the RSDP ACPI table in the memory starting at addr and + * ending at addr + len - 1. + */ +static struct rsdp_descriptor * +find_rsdp(u8 *start, unsigned int len) +{ + u8 *end = start + len; + + /* scan memory in steps of 16 bytes */ + while (start < end) { + /* check for expected string */ + if (RSDP_CAST(start)->signature == RSDP_SIGNATURE && + calc_checksum(start, + sizeof(struct rsdp_descriptor)) == 0) + return RSDP_CAST(start); + start += 0x10; + } + + return 0; +} + + + + +static struct tcpa_descriptor_rev2 * +find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) +{ + u32 ctr = 0; + struct tcpa_descriptor_rev2 *tcpa = NULL; + struct rsdt_descriptor *rsdt; + u32 length; + u16 off; + + rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address; + if (!rsdt) + return NULL; + + length = rsdt->length; + off = offsetof(struct rsdt_descriptor, entry); + + while ((off + sizeof(rsdt->entry[0])) <= length) { + /* try all pointers to structures */ + tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr]; + + /* valid TCPA ACPI table ? */ + if (tcpa->signature == TCPA_SIGNATURE && + calc_checksum((u8 *)tcpa, tcpa->length) == 0) + break; + + tcpa = NULL; + off += sizeof(rsdt->entry[0]); + ctr++; + } + + return tcpa; +} + + +static struct tcpa_descriptor_rev2 * +find_tcpa_table(void) +{ + struct tcpa_descriptor_rev2 *tcpa = NULL; + struct rsdp_descriptor *rsdp; + u16 ebda_seg; + + /* RSDP in EBDA? */ + ebda_seg = *(u16 *)MAKE_FLATPTR(0x40, 0xe); + rsdp = find_rsdp(MAKE_FLATPTR(ebda_seg, 0), 1024); + + if (rsdp) + tcpa = find_tcpa_by_rsdp(rsdp); + + if (!tcpa) { + rsdp = find_rsdp((u8 *)0xE0000, 0x20000); + if (rsdp) + tcpa = find_tcpa_by_rsdp(rsdp); + } + + if (!rsdp) + tcpa_state.if_shutdown = 1; + +#ifdef DEBUG_TCGBIOS + if (! rsdp ) + dprintf(1, "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n"); + else if ( !tcpa ) + dprintf(1, "TCGBIOS: TCPA ACPI was NOT found!\n"); +#endif + + return tcpa; +} + + +static u8 * +get_lasa_base_ptr(u32 *laml) +{ + u8 *lasa = 0; + struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table(); + + if (tcpa) { + lasa = (u8 *)(long)tcpa->lasa; + if (laml) + *laml = tcpa->laml; + } + + return lasa; +} + + +/* clear the ACPI log */ +static void +reset_acpi_log(void) +{ + u32 laml; + u8 *lasa = get_lasa_base_ptr(&laml); + + if (lasa) + memset(lasa, 0x0, laml); +} + + +/* + initialize the TCPA ACPI subsystem; find the ACPI tables and determine + where the TCPA table is. + */ +void +tcpa_acpi_init(void) +{ + tcpa_state.if_shutdown = 0; + tcpa_state.tpm_probed = 0; + tcpa_state.tpm_found = 0; + tcpa_state.tpm_working = 0; + + if (!has_working_tpm()) { + tcpa_state.if_shutdown = 1; + return; + } + + reset_acpi_log(); +} + + +static u32 +transmit(u8 locty, const struct iovec iovec[], + u8 *respbuffer, u32 *respbufferlen) +{ + u32 rc = 0; + u32 irc; + struct tpm_driver *td; + unsigned int i; + + if (tcpa_state.tpm_driver_to_use == TPM_INVALID_DRIVER) + return TCG_FATAL_COM_ERROR; + + td = &tpm_drivers[tcpa_state.tpm_driver_to_use]; + + irc = td->activate(locty); + if (irc != 0) { + /* tpm could not be activated */ + return TCG_FATAL_COM_ERROR; + } + + for (i = 0; iovec[i].length; i++) { + irc = td->senddata(iovec[i].data, + iovec[i].length); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + } + + irc = td->waitdatavalid(); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + irc = td->waitrespready(10000); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + irc = td->readresp(respbuffer, + respbufferlen); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + td->ready(); + + return rc; +} + + +/* + * Send a TPM command with the given ordinal. Append the given buffer + * containing all data in network byte order to the command (this is + * the custom part per command) and expect a response of the given size. + * If a buffer is provided, the response will be copied into it. + */ +static u32 +build_and_send_cmd_od(u32 ordinal, const u8 *append, u32 append_size, + u8 *resbuffer, u32 return_size, u32 *returnCode, + const u8 *otherdata, u32 otherdata_size) +{ +#define MAX_APPEND_SIZE 12 +#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags) + u32 rc; + u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE]; + u8 obuffer[MAX_RESPONSE_SIZE]; + struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer; + struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer; + u8 locty = 0; + struct iovec iovec[3]; + u32 obuffer_len = sizeof(obuffer); + u32 idx = 1; + + if (append_size > MAX_APPEND_SIZE || + return_size > MAX_RESPONSE_SIZE) { +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: size of requested buffers too big."); +#endif + return TCG_FIRMWARE_ERROR; + } + + iovec[0].data = trqh; + iovec[0].length = TPM_REQ_HEADER_SIZE + append_size; + + if (otherdata) { + iovec[1].data = (void *)otherdata; + iovec[1].length = otherdata_size; + idx = 2; + } + + iovec[idx].data = NULL; + iovec[idx].length = 0; + + memset(ibuffer, 0x0, sizeof(ibuffer)); + memset(obuffer, 0x0, sizeof(obuffer)); + + trqh->tag = htons(0xc1); + trqh->totlen = htonl(TPM_REQ_HEADER_SIZE + append_size + otherdata_size); + trqh->ordinal = htonl(ordinal); + + if (append_size) + memcpy((char *)trqh + sizeof(*trqh), + append, append_size); + + rc = transmit(locty, iovec, obuffer, &obuffer_len); + if (rc) + return rc; + + *returnCode = ntohl(trsh->errcode); + + if (resbuffer) + memcpy(resbuffer, trsh, return_size); + + return 0; +} + + +static u32 +build_and_send_cmd(u32 ordinal, const u8 *append, u32 append_size, + u8 *resbuffer, u32 return_size, u32 *returnCode) +{ + return build_and_send_cmd_od(ordinal, append, append_size, + resbuffer, return_size, returnCode, + NULL, 0); +} + + +u32 +tcpa_startup(void) +{ + u32 rc = 0; + u32 returnCode; + + if (!has_working_tpm()) + return 0; + +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n"); +#endif + rc = build_and_send_cmd(TPM_ORD_Startup, + Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR), + NULL, 10, &returnCode); +#ifdef DEBUG_TCGBIOS + dprintf(1,"Return code from TPM_Startup = 0x%08x\n", + returnCode); +#endif + if (rc && returnCode) + goto err_exit; + + rc = build_and_send_cmd(TPM_ORD_SelfTestFull, NULL, 0, + NULL, 10, &returnCode); +#ifdef DEBUG_TCGBIOS + dprintf(1,"Return code from TPM_SelfTestFull = 0x%08x\n", + returnCode); +#endif + if (rc || returnCode) + goto err_exit; + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +u32 +tcpa_leave_bios(void) +{ + u32 rc = 0; + u32 returnCode; + + if (!has_working_tpm()) + return 0; + + rc = build_and_send_cmd(TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + NULL, 10, &returnCode); + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(TPM_ORD_PhysicalPresence, + PhysicalPresence_NOT_PRESENT, + sizeof(PhysicalPresence_NOT_PRESENT), + NULL, 10, &returnCode); + if (rc || returnCode) + goto err_exit; + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +u32 +tcpa_s3_resume(void) +{ + u32 rc = 0; + u32 returnCode; + + if (has_working_tpm()) { + rc = build_and_send_cmd(TPM_ORD_Startup, + Startup_ST_STATE, + sizeof(Startup_ST_STATE), + NULL, 10, &returnCode); +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n"); + dprintf(1,"TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n", + returnCode); +#endif + if (rc || returnCode) + goto err_exit; + } + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +#endif /* CONFIG_TCGBIOS */ Index: seabios/src/tcgbios.h =================================================================== --- /dev/null +++ seabios/src/tcgbios.h @@ -0,0 +1,386 @@ +#ifndef TCGBIOS_H +#define TCGBIOS_H + +#include "types.h" +#include "bregs.h" /* struct bregs */ + +#define TCG_MAGIC 0x41504354L + +/* Define for section 12.3 */ +#define TCG_PC_OK 0x0 +#define TCG_PC_TPMERROR 0x1 +#define TCG_PC_LOGOVERFLOW 0x2 +#define TCG_PC_UNSUPPORTED 0x3 + +#define TPM_ALG_SHA 0x4 + +#define TCG_MAGIC 0x41504354L +#define TCG_VERSION_MAJOR 1 +#define TCG_VERSION_MINOR 2 + +#define TPM_OK 0x0 +#define TPM_RET_BASE 0x1 +#define TCG_GENERAL_ERROR (TPM_RET_BASE + 0x0) +#define TCG_TPM_IS_LOCKED (TPM_RET_BASE + 0x1) +#define TCG_NO_RESPONSE (TPM_RET_BASE + 0x2) +#define TCG_INVALID_RESPONSE (TPM_RET_BASE + 0x3) +#define TCG_INVALID_ACCESS_REQUEST (TPM_RET_BASE + 0x4) +#define TCG_FIRMWARE_ERROR (TPM_RET_BASE + 0x5) +#define TCG_INTEGRITY_CHECK_FAILED (TPM_RET_BASE + 0x6) +#define TCG_INVALID_DEVICE_ID (TPM_RET_BASE + 0x7) +#define TCG_INVALID_VENDOR_ID (TPM_RET_BASE + 0x8) +#define TCG_UNABLE_TO_OPEN (TPM_RET_BASE + 0x9) +#define TCG_UNABLE_TO_CLOSE (TPM_RET_BASE + 0xa) +#define TCG_RESPONSE_TIMEOUT (TPM_RET_BASE + 0xb) +#define TCG_INVALID_COM_REQUEST (TPM_RET_BASE + 0xc) +#define TCG_INVALID_ADR_REQUEST (TPM_RET_BASE + 0xd) +#define TCG_WRITE_BYTE_ERROR (TPM_RET_BASE + 0xe) +#define TCG_READ_BYTE_ERROR (TPM_RET_BASE + 0xf) +#define TCG_BLOCK_WRITE_TIMEOUT (TPM_RET_BASE + 0x10) +#define TCG_CHAR_WRITE_TIMEOUT (TPM_RET_BASE + 0x11) +#define TCG_CHAR_READ_TIMEOUT (TPM_RET_BASE + 0x12) +#define TCG_BLOCK_READ_TIMEOUT (TPM_RET_BASE + 0x13) +#define TCG_TRANSFER_ABORT (TPM_RET_BASE + 0x14) +#define TCG_INVALID_DRV_FUNCTION (TPM_RET_BASE + 0x15) +#define TCG_OUTPUT_BUFFER_TOO_SHORT (TPM_RET_BASE + 0x16) +#define TCG_FATAL_COM_ERROR (TPM_RET_BASE + 0x17) +#define TCG_INVALID_INPUT_PARA (TPM_RET_BASE + 0x18) +#define TCG_TCG_COMMAND_ERROR (TPM_RET_BASE + 0x19) +#define TCG_INTERFACE_SHUTDOWN (TPM_RET_BASE + 0x20) +//define TCG_PC_UNSUPPORTED (TPM_RET_BASE + 0x21) +#define TCG_PC_TPM_NOT_PRESENT (TPM_RET_BASE + 0x22) +#define TCG_PC_TPM_DEACTIVATED (TPM_RET_BASE + 0x23) + + +#define TPM_INVALID_ADR_REQUEST TCG_INVALID_ADR_REQUEST +#define TPM_IS_LOCKED TCG_TPM_IS_LOCKED +#define TPM_INVALID_DEVICE_ID TCG_INVALID_DEVICE_ID +#define TPM_INVALID_VENDOR_ID TCG_INVALID_VENDOR_ID +//define TPM_RESERVED_REG_INVALID +#define TPM_FIRMWARE_ERROR TCG_FIRMWARE_ERROR +#define TPM_UNABLE_TO_OPEN TCG_UNABLE_TO_OPEN +#define TPM_UNABLE_TO_CLOSE TCG_UNABLE_TO_CLOSE +#define TPM_INVALID_RESPONSE TCG_INVALID_RESPONSE +#define TPM_RESPONSE_TIMEOUT TCG_RESPONSE_TIMEOUT +#define TPM_INVALID_ACCESS_REQUEST TCG_INVALID_ACCESS_REQUEST +#define TPM_TRANSFER_ABORT TCG_TRANSFER_ABORT +#define TPM_GENERAL_ERROR TCG_GENERAL_ERROR + + +#define TPM_ORD_SelfTestFull 0x00000050 +#define TPM_ORD_ForceClear 0x0000005d +#define TPM_ORD_GetCapability 0x00000065 +#define TPM_ORD_PhysicalEnable 0x0000006f +#define TPM_ORD_PhysicalDisable 0x00000070 +#define TPM_ORD_SetOwnerInstall 0x00000071 +#define TPM_ORD_PhysicalSetDeactivated 0x00000072 +#define TPM_ORD_Startup 0x00000099 +#define TPM_ORD_PhysicalPresence 0x4000000a +#define TPM_ORD_Extend 0x00000014 +#define TPM_ORD_SHA1Start 0x000000a0 +#define TPM_ORD_SHA1Update 0x000000a1 +#define TPM_ORD_SHA1Complete 0x000000a2 + + +#define TPM_ST_CLEAR 0x1 +#define TPM_ST_STATE 0x2 +#define TPM_ST_DEACTIVATED 0x3 + + +/* interrupt identifiers (al register) */ +enum irq_ids { + TCG_StatusCheck = 0, + TCG_HashLogExtendEvent = 1, + TCG_PassThroughToTPM = 2, + TCG_ShutdownPreBootInterface = 3, + TCG_HashLogEvent = 4, + TCG_HashAll = 5, + TCG_TSS = 6, + TCG_CompactHashLogExtendEvent = 7, +}; + +/* event types: 10.4.1 / table 11 */ +#define EV_POST_CODE 1 +#define EV_SEPARATOR 4 +#define EV_ACTION 5 +#define EV_EVENT_TAG 6 +#define EV_COMPACT_HASH 12 +#define EV_IPL 13 +#define EV_IPL_PARTITION_DATA 14 + + +#define STATUS_FLAG_SHUTDOWN (1 << 0) + +#define SHA1_BUFSIZE 20 + + +struct iovec +{ + size_t length; + void *data; +}; + + +/* Input and Output blocks for the TCG BIOS commands */ + +struct hleei_short +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + const void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleei_long +{ + u16 ipblength; + u16 reserved; + void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + u32 reserved2; + void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleeo +{ + u16 opblength; + u16 reserved; + u32 eventnumber; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct pttti +{ + u16 ipblength; + u16 reserved; + u16 opblength; + u16 reserved2; + u8 tpmopin[0]; +} PACKED; + + +struct pttto +{ + u16 opblength; + u16 reserved; + u8 tpmopout[0]; +}; + + +struct hlei +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + u32 logeventtype; + const void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleo +{ + u16 opblength; + u16 reserved; + u32 eventnumber; +} PACKED; + + +struct hai +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 algorithmid; +} PACKED; + + +struct ti +{ + u16 ipblength; + u16 reserved; + u16 opblength; + u16 reserved2; + u8 tssoperandin[0]; +} PACKED; + + +struct to +{ + u16 opblength; + u16 reserved; + u8 tssoperandout[0]; +} PACKED; + + +struct pcpes +{ + u32 pcrindex; + u32 eventtype; + u8 digest[SHA1_BUFSIZE]; + u32 eventdatasize; + u32 event; +} PACKED; + + +/* 10.4.2.1 */ +struct pcctes +{ + u32 eventid; + u32 eventdatasize; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + +/* 10.4.2.1 w/ 10.4.2.2.1 embedded */ +struct pcctes_romex +{ + u32 eventid; + u32 eventdatasize; + u16 reserved; + u16 pfa; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +#define TPM_REQ_HEADER \ + u16 tag; \ + u32 totlen; \ + u32 ordinal; + +#define TPM_REQ_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32)) + +#define TPM_RSP_HEADER \ + u16 tag; \ + u32 totlen; \ + u32 errcode; + +#define TPM_RSP_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32)) + +struct tpm_req_header { + TPM_REQ_HEADER; +} PACKED; + + +struct tpm_rsp_header { + TPM_RSP_HEADER; +} PACKED; + + +struct tpm_req_extend { + TPM_REQ_HEADER + u32 pcrindex; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct tpm_rsp_extend { + TPM_RSP_HEADER + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct tpm_req_getcap_perm_flags { + TPM_REQ_HEADER + u32 capArea; + u32 subCapSize; + u32 subCap; +} PACKED; + + +struct tpm_permanent_flags { + u16 tag; + u8 flags[20]; +} PACKED; + + +enum permFlagsIndex { + PERM_FLAG_IDX_DISABLE = 0, + PERM_FLAG_IDX_OWNERSHIP, + PERM_FLAG_IDX_DEACTIVATED, + PERM_FLAG_IDX_READPUBEK, + PERM_FLAG_IDX_DISABLEOWNERCLEAR, + PERM_FLAG_IDX_ALLOW_MAINTENANCE, + PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK, + PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE, +}; + + +struct tpm_res_getcap_perm_flags { + TPM_RSP_HEADER + u32 size; + struct tpm_permanent_flags perm_flags; +} PACKED; + + +struct tpm_res_getcap_ownerauth { + TPM_RSP_HEADER + u32 size; + u8 flag; +} PACKED; + + +struct tpm_res_sha1start { + TPM_RSP_HEADER + u32 max_num_bytes; +} PACKED; + + +struct tpm_res_sha1complete { + TPM_RSP_HEADER + u8 hash[20]; +} PACKED; + +struct pttti_extend { + struct pttti pttti; + struct tpm_req_extend req; +} PACKED; + + +struct pttto_extend { + struct pttto pttto; + struct tpm_rsp_extend rsp; +} PACKED; + + +enum ipltype { + IPL_BCV = 0, + IPL_EL_TORITO_1, + IPL_EL_TORITO_2 +}; + +#if CONFIG_TCGBIOS +void tcpa_acpi_init(void); +int has_working_tpm(void); +u32 tcpa_startup(void); +u32 tcpa_leave_bios(void); +u32 tcpa_s3_resume(void); +#else +static inline void tcpa_acpi_init(void) { +} +static inline int has_working_tpm(void) { + return 0; +} +static inline u32 tcpa_startup(void) { + return 0; +} +static inline u32 tcpa_leave_bios(void) { + return 0; +} +static inline u32 tcpa_s3_resume(void) { + return 0; +} +#endif +void tcpa_menu(void); + +#endif /* TCGBIOS_H */ Index: seabios/src/util.c =================================================================== --- seabios.orig/src/util.c +++ seabios/src/util.c @@ -322,3 +322,21 @@ get_keystroke(int msec) wait_irq(); } } + + +// wait a given time +// this function also works in case of a resume +void +mssleep(u32 msec) +{ + u32 i; + u8 x, y = inb(0x61) & 0x10; + + /* Poll the DRAM refresh timer: I/O port 61h, bit 4 toggles every 15us. */ + msec *= (1000/15); /* Convert milliseconds to multiples of 15us. */ + for ( i = 0; i < msec; i++ ) { + while ( (x = inb(0x61) & 0x10) == y ) + continue; + y = x; + } +} Index: seabios/src/util.h =================================================================== --- seabios.orig/src/util.h +++ seabios/src/util.h @@ -497,4 +497,9 @@ extern u8 BiosChecksum; // version (auto generated file out/version.c) extern const char VERSION[];
+ +void mssleep(u32 time); + +void tcpa_interrupt_handler16(struct bregs *regs); + #endif // util.h Index: seabios/src/post.c =================================================================== --- seabios.orig/src/post.c +++ seabios/src/post.c @@ -25,6 +25,7 @@ #include "paravirt.h" // qemu_cfg_port_probe #include "ps2port.h" // ps2port_setup #include "virtio-blk.h" // virtio_blk_setup +#include "tcgbios.h" // tcpa_*
/**************************************************************** @@ -238,6 +239,10 @@ maininit(void) mouse_setup(); init_bios_tables();
+ // Initialize tpm (after acpi tables were written) + tcpa_acpi_init(); + tcpa_startup(); + // Run vga option rom vga_setup();
Index: seabios/src/boot.c =================================================================== --- seabios.orig/src/boot.c +++ seabios/src/boot.c @@ -14,6 +14,7 @@ #include "cmos.h" // inb_cmos #include "paravirt.h" // romfile_loadfile #include "pci.h" //pci_bdf_to_* +#include "tcgbios.h" // tcpa_*
/**************************************************************** @@ -449,6 +450,7 @@ boot_prep(void) // Allow user to modify BCV/IPL order. interactive_bootmenu(); wait_threads(); + tcpa_leave_bios();
// Map drives and populate BEV list struct bootentry_s *pos = BootList; Index: seabios/src/resume.c =================================================================== --- seabios.orig/src/resume.c +++ seabios/src/resume.c @@ -10,6 +10,7 @@ #include "biosvar.h" // struct bios_data_area_s #include "bregs.h" // struct bregs #include "acpi.h" // find_resume_vector +#include "tcgbios.h" // tcpa_s3_resume
// Reset DMA controller void @@ -116,6 +117,7 @@ s3_resume(void) if (s3_resume_vector) { dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector); br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector); + tcpa_s3_resume(); } else { dprintf(1, "No resume vector set!\n"); // Jump to the post vector to restart with a normal boot.