aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--src/Kconfig7
-rw-r--r--src/config.h1
-rw-r--r--src/hw/tpm_drivers.c33
-rw-r--r--src/post.c7
-rw-r--r--src/resume.c3
-rw-r--r--src/std/acpi.h20
-rw-r--r--src/tcgbios.c572
-rw-r--r--src/tcgbios.h386
9 files changed, 1032 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 3ee61af..165da33 100644
--- a/Makefile
+++ b/Makefile
@@ -38,11 +38,12 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c
SRC16=$(SRCBOTH)
SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \
- pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c \
+ pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c \
hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \
fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \
fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \
- fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c
+ fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \
+ hw/tpm_drivers.c
SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c
DIRS=src src/hw src/fw vgasrc
diff --git a/src/Kconfig b/src/Kconfig
index 45ca59c..19f4db1 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -421,6 +421,13 @@ menu "BIOS interfaces"
modified by programs. However, some old DOS high memory
managers may require the UMB region to be read-only.
+ config TCGBIOS
+ depends on S3_RESUME
+ bool "TPM support and TCG BIOS extensions"
+ default y
+ help
+ Provide TPM support along with TCG BIOS extensions
+
endmenu
menu "BIOS Tables"
diff --git a/src/config.h b/src/config.h
index 6da067d..4bfebe8 100644
--- a/src/config.h
+++ b/src/config.h
@@ -104,5 +104,6 @@
#define DEBUG_unimplemented 2
#define DEBUG_invalid 3
#define DEBUG_thread 2
+#define DEBUG_tcg 20
#endif // config.h
diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c
index ea602e8..444eac3 100644
--- a/src/hw/tpm_drivers.c
+++ b/src/hw/tpm_drivers.c
@@ -35,6 +35,9 @@ static u32 tpm_default_to[4];
/* if device is not there, return '0', '1' otherwise */
static u32 tis_probe(void)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 0;
u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));
@@ -46,6 +49,9 @@ static u32 tis_probe(void)
static u32 tis_init(void)
{
+ if (!CONFIG_TCGBIOS)
+ return 1;
+
writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);
if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) {
@@ -68,6 +74,9 @@ static u32 tis_init(void)
static void set_timeouts(u32 timeouts[4], u32 durations[3])
{
+ if (!CONFIG_TCGBIOS)
+ return;
+
u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts;
u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations;
@@ -80,6 +89,9 @@ static void set_timeouts(u32 timeouts[4], u32 durations[3])
static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 1;
while (time > 0) {
@@ -96,6 +108,9 @@ static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
static u32 tis_activate(u8 locty)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 0;
u8 acc;
int l;
@@ -124,6 +139,9 @@ static u32 tis_activate(u8 locty)
static u32 tis_find_active_locality(void)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u8 locty;
for (locty = 0; locty <= 4; locty++) {
@@ -139,6 +157,9 @@ static u32 tis_find_active_locality(void)
static u32 tis_ready(void)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 0;
u8 locty = tis_find_active_locality();
u32 timeout_b = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B];
@@ -152,6 +173,9 @@ static u32 tis_ready(void)
static u32 tis_senddata(const u8 *const data, u32 len)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 0;
u32 offset = 0;
u32 end = 0;
@@ -191,6 +215,9 @@ static u32 tis_senddata(const u8 *const data, u32 len)
static u32 tis_readresp(u8 *buffer, u32 *len)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 0;
u32 offset = 0;
u32 sts;
@@ -213,6 +240,9 @@ static u32 tis_readresp(u8 *buffer, u32 *len)
static u32 tis_waitdatavalid(void)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 0;
u8 locty = tis_find_active_locality();
u32 timeout_c = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];
@@ -225,6 +255,9 @@ static u32 tis_waitdatavalid(void)
static u32 tis_waitrespready(enum tpmDurationType to_t)
{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
u32 rc = 0;
u8 locty = tis_find_active_locality();
u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t];
diff --git a/src/post.c b/src/post.c
index 9ea5620..0c7b36b 100644
--- a/src/post.c
+++ b/src/post.c
@@ -28,6 +28,7 @@
#include "output.h" // dprintf
#include "string.h" // memset
#include "util.h" // kbd_init
+#include "tcgbios.h" // tpm_*
/****************************************************************
@@ -220,6 +221,9 @@ maininit(void)
if (threads_during_optionroms())
device_hardware_setup();
+ // Initialize TPM
+ tpm_start();
+
// Run vga option rom
vgarom_setup();
@@ -236,6 +240,9 @@ maininit(void)
interactive_bootmenu();
wait_threads();
+ // Change TPM phys. presence state befor leaving BIOS
+ tpm_leave_bios();
+
// Prepare for boot.
prepareboot();
diff --git a/src/resume.c b/src/resume.c
index 1903174..a5465d8 100644
--- a/src/resume.c
+++ b/src/resume.c
@@ -16,6 +16,7 @@
#include "std/bda.h" // struct bios_data_area_s
#include "string.h" // memset
#include "util.h" // dma_setup
+#include "tcgbios.h" // tpm_s3_resume
// Handler for post calls that look like a resume.
void VISIBLE16
@@ -99,6 +100,8 @@ s3_resume(void)
pci_resume();
+ /* resume TPM before we may measure option roms */
+ tpm_s3_resume();
s3_resume_vga();
make_bios_readonly();
diff --git a/src/std/acpi.h b/src/std/acpi.h
index e0d9516..b672bbe 100644
--- a/src/std/acpi.h
+++ b/src/std/acpi.h
@@ -294,4 +294,24 @@ struct acpi_table_mcfg {
struct acpi_mcfg_allocation allocation[0];
} PACKED;
+
+struct rsdt_descriptor {
+ ACPI_TABLE_HEADER_DEF
+ u32 entry[1];
+} PACKED;
+
+#define TCPA_SIGNATURE 0x41504354
+struct tcpa_descriptor_rev2
+{
+ ACPI_TABLE_HEADER_DEF
+ u16 platform_class;
+ u32 log_area_minimum_length;
+ u64 log_area_start_address;
+} PACKED;
+
+/* TCPA ACPI definitions */
+#define TCPA_ACPI_CLASS_CLIENT 0
+#define TCPA_ACPI_CLASS_SERVER 1
+
+
#endif // acpi.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
new file mode 100644
index 0000000..73ff1f3
--- /dev/null
+++ b/src/tcgbios.c
@@ -0,0 +1,572 @@
+// Implementation of the TCG BIOS extension according to the specification
+// described in
+// https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
+//
+// Copyright (C) 2006-2011, 2014 IBM Corporation
+//
+// Authors:
+// Stefan Berger <stefanb@linux.vnet.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+#include "config.h"
+
+#include "types.h"
+#include "byteorder.h" // cpu_to_*
+#include "hw/tpm_drivers.h" // tpm_drivers[]
+#include "farptr.h" // MAKE_FLATPTR
+#include "string.h" // checksum
+#include "tcgbios.h"// tpm_*, prototypes
+#include "util.h" // printf, get_keystroke
+#include "output.h" // dprintf
+#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
+#include "bregs.h" // struct bregs
+
+
+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_LOCK[2] = { 0x00, 0x14 };
+
+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
+};
+
+static const u8 GetCapability_Timeouts[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x15
+};
+
+static const u8 GetCapability_Durations[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x20
+};
+
+
+#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;
+} tpm_state_t;
+
+
+static tpm_state_t tpm_state = {
+ .tpm_driver_to_use = TPM_INVALID_DRIVER,
+};
+
+
+/********************************************************
+ 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();
+ tpm_state.tpm_driver_to_use = i;
+ rc = 1;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static void
+probe_tpm(void)
+{
+ if (!tpm_state.tpm_probed) {
+ tpm_state.tpm_probed = 1;
+ tpm_state.tpm_found = (is_tpm_present() != 0);
+ tpm_state.tpm_working = tpm_state.tpm_found;
+ }
+}
+
+static int
+has_working_tpm(void)
+{
+ probe_tpm();
+
+ return tpm_state.tpm_working;
+}
+
+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 &&
+ 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 = RsdpAddr;
+
+ if (rsdp)
+ tcpa = find_tcpa_by_rsdp(rsdp);
+ else
+ tpm_state.if_shutdown = 1;
+
+ if (!rsdp)
+ dprintf(DEBUG_tcg,
+ "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
+ else if (!tcpa)
+ dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
+
+ return tcpa;
+}
+
+
+static u8 *
+get_lasa_base_ptr(u32 *log_area_minimum_length)
+{
+ u8 *log_area_start_address = 0;
+ struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
+
+ if (tcpa) {
+ log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
+ if (log_area_minimum_length)
+ *log_area_minimum_length = tcpa->log_area_minimum_length;
+ }
+
+ return log_area_start_address;
+}
+
+
+/* clear the ACPI log */
+static void
+reset_acpi_log(void)
+{
+ u32 log_area_minimum_length;
+ u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
+
+ if (log_area_start_address)
+ memset(log_area_start_address, 0x0, log_area_minimum_length);
+}
+
+
+/*
+ initialize the TCPA ACPI subsystem; find the ACPI tables and determine
+ where the TCPA table is.
+ */
+static void
+tpm_acpi_init(void)
+{
+ tpm_state.if_shutdown = 0;
+ tpm_state.tpm_probed = 0;
+ tpm_state.tpm_found = 0;
+ tpm_state.tpm_working = 0;
+
+ if (!has_working_tpm()) {
+ tpm_state.if_shutdown = 1;
+ return;
+ }
+
+ reset_acpi_log();
+}
+
+
+static u32
+transmit(u8 locty, const struct iovec iovec[],
+ u8 *respbuffer, u32 *respbufferlen,
+ enum tpmDurationType to_t)
+{
+ u32 rc = 0;
+ u32 irc;
+ struct tpm_driver *td;
+ unsigned int i;
+
+ if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
+ return TCG_FATAL_COM_ERROR;
+
+ td = &tpm_drivers[tpm_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(to_t);
+ 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,
+ enum tpmDurationType to_t)
+{
+#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) {
+ dprintf(DEBUG_tcg, "TCGBIOS: size of requested buffers too big.");
+ 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 = cpu_to_be16(0xc1);
+ trqh->totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size + otherdata_size);
+ trqh->ordinal = cpu_to_be32(ordinal);
+
+ if (append_size)
+ memcpy((char *)trqh + sizeof(*trqh),
+ append, append_size);
+
+ rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
+ if (rc)
+ return rc;
+
+ *returnCode = be32_to_cpu(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,
+ enum tpmDurationType to_t)
+{
+ return build_and_send_cmd_od(ordinal, append, append_size,
+ resbuffer, return_size, returnCode,
+ NULL, 0, to_t);
+}
+
+
+static u32
+determine_timeouts(void)
+{
+ u32 rc;
+ u32 returnCode;
+ struct tpm_res_getcap_timeouts timeouts;
+ struct tpm_res_getcap_durations durations;
+ struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
+ u32 i;
+
+ rc = build_and_send_cmd(TPM_ORD_GetCapability,
+ GetCapability_Timeouts,
+ sizeof(GetCapability_Timeouts),
+ (u8 *)&timeouts,
+ sizeof(struct tpm_res_getcap_timeouts),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
+ " = 0x%08x\n", returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(TPM_ORD_GetCapability,
+ GetCapability_Durations,
+ sizeof(GetCapability_Durations),
+ (u8 *)&durations,
+ sizeof(struct tpm_res_getcap_durations),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
+ " = 0x%08x\n", returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ for (i = 0; i < 3; i++)
+ durations.durations[i] = be32_to_cpu(durations.durations[i]);
+
+ for (i = 0; i < 4; i++)
+ timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
+ timeouts.timeouts[0],
+ timeouts.timeouts[1],
+ timeouts.timeouts[2],
+ timeouts.timeouts[3]);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
+ durations.durations[0],
+ durations.durations[1],
+ durations.durations[2]);
+
+
+ td->set_timeouts(timeouts.timeouts, durations.durations);
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+tpm_startup(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
+ rc = build_and_send_cmd(TPM_ORD_Startup,
+ Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
+ NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
+ returnCode);
+
+ if (CONFIG_COREBOOT) {
+ /* with other firmware on the system the TPM may already have been
+ * initialized
+ */
+ if (returnCode == TPM_INVALID_POSTINIT)
+ returnCode = 0;
+ }
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(TPM_ORD_SelfTestFull, NULL, 0,
+ NULL, 10, &returnCode, TPM_DURATION_TYPE_LONG);
+
+ dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
+ returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(TSC_ORD_ResetEstablishmentBit, NULL, 0,
+ NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
+ returnCode);
+
+ if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
+ goto err_exit;
+
+ rc = determine_timeouts();
+ if (rc)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+u32
+tpm_start(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ tpm_acpi_init();
+
+ return tpm_startup();
+}
+
+
+u32
+tpm_leave_bios(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+ PhysicalPresence_CMD_ENABLE,
+ sizeof(PhysicalPresence_CMD_ENABLE),
+ NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+ PhysicalPresence_NOT_PRESENT_LOCK,
+ sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
+ NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+ if (rc || returnCode)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+u32
+tpm_s3_resume(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
+
+ rc = build_and_send_cmd(TPM_ORD_Startup,
+ Startup_ST_STATE, sizeof(Startup_ST_STATE),
+ NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
+ returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
diff --git a/src/tcgbios.h b/src/tcgbios.h
new file mode 100644
index 0000000..c6abd2c
--- /dev/null
+++ b/src/tcgbios.h
@@ -0,0 +1,386 @@
+#ifndef TCGBIOS_H
+#define TCGBIOS_H
+
+#include "types.h"
+
+#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 TSC_ORD_ResetEstablishmentBit 0x4000000b
+
+
+#define TPM_ST_CLEAR 0x1
+#define TPM_ST_STATE 0x2
+#define TPM_ST_DEACTIVATED 0x3
+
+
+/* TPM command error codes */
+#define TPM_INVALID_POSTINIT 0x26
+#define TPM_BAD_LOCALITY 0x3d
+
+
+/* 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_getcap_timeouts {
+ TPM_RSP_HEADER
+ u32 size;
+ u32 timeouts[4];
+} PACKED;
+
+
+struct tpm_res_getcap_durations {
+ TPM_RSP_HEADER
+ u32 size;
+ u32 durations[3];
+} 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
+};
+
+
+u32 tpm_start(void);
+u32 tpm_leave_bios(void);
+u32 tpm_s3_resume(void);
+
+#endif /* TCGBIOS_H */