diff mbox series

[v4,02/33] tpm: Add TPM initialization support

Message ID 20191211202728.127996-3-stefanb@linux.vnet.ibm.com
State Superseded
Headers show
Series Add vTPM support to SLOF | expand

Commit Message

Stefan Berger Dec. 11, 2019, 8:26 p.m. UTC
This patch implements the main part of the firmware extensions. It provides
the following functionality:

- initialization of the TPM by sending a sequence of commands to it
- proper setup of the TPM before the firmware hands over control to the bootloader

Structures that are needed in subsequent patches are also included in the
private header file tcgbios_int.h at this point.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 board-qemu/Makefile                 |   2 +-
 board-qemu/slof/Makefile            |  13 +-
 board-qemu/slof/tree.fs             |   3 +
 board-qemu/slof/vio-vtpm-cdriver.fs |  72 ++++++++
 board-qemu/slof/vtpm-sml.fs         |  62 +++++++
 lib/Makefile                        |   2 +-
 lib/libtpm/Makefile                 |   2 +-
 lib/libtpm/tcgbios.c                | 271 ++++++++++++++++++++++++++++
 lib/libtpm/tcgbios.h                |  22 +++
 lib/libtpm/tcgbios_int.h            | 153 ++++++++++++++++
 lib/libtpm/tpm.code                 |  46 +++++
 lib/libtpm/tpm.in                   |  18 ++
 lib/libtpm/tpm_drivers.c            |  13 ++
 lib/libtpm/tpm_drivers.h            |   5 +
 slof/fs/start-up.fs                 |   7 +
 15 files changed, 685 insertions(+), 6 deletions(-)
 create mode 100644 board-qemu/slof/vio-vtpm-cdriver.fs
 create mode 100644 board-qemu/slof/vtpm-sml.fs
 create mode 100644 lib/libtpm/tcgbios.c
 create mode 100644 lib/libtpm/tcgbios.h
 create mode 100644 lib/libtpm/tcgbios_int.h
 create mode 100644 lib/libtpm/tpm.code
 create mode 100644 lib/libtpm/tpm.in
diff mbox series

Patch

diff --git a/board-qemu/Makefile b/board-qemu/Makefile
index 61a1367..f419202 100644
--- a/board-qemu/Makefile
+++ b/board-qemu/Makefile
@@ -15,7 +15,7 @@  BOARD_TARGETS = tools_build romfs_build stage1 subdirs
 SUBDIRS = slof
 
 COMMON_LIBS = libc libbootmsg libbases libnvram libelf libhvcall libvirtio \
-              libusb libveth libe1k libnet libbootmenu
+              libusb libveth libe1k libnet libbootmenu libtpm
 
 all: $(BOARD_TARGETS)
 	$(MAKE) boot_rom.bin
diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile
index d7ed2d7..a8cff6d 100644
--- a/board-qemu/slof/Makefile
+++ b/board-qemu/slof/Makefile
@@ -22,7 +22,8 @@  CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \
 	   -I$(LIBCMNDIR)/libvirtio -I$(LIBCMNDIR)/libnvram \
 	   -I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libveth \
 	   -I$(LIBCMNDIR)/libe1k -I$(LIBCMNDIR)/libnet \
-	   -I$(LIBCMNDIR)/libbootmenu
+	   -I$(LIBCMNDIR)/libbootmenu -I$(LIBCMNDIR)/libtpm
+
 SLOF_LIBS = \
 	$(LIBCMNDIR)/libbootmsg.a \
 	$(LIBCMNDIR)/libelf.a \
@@ -33,7 +34,9 @@  SLOF_LIBS = \
 	$(LIBCMNDIR)/libveth.a \
 	$(LIBCMNDIR)/libe1k.a \
 	$(LIBCMNDIR)/libnet.a \
-	$(LIBCMNDIR)/libbootmenu.a
+	$(LIBCMNDIR)/libbootmenu.a \
+	$(LIBCMNDIR)/libtpm.a
+
 BOARD_SLOF_IN = \
 	$(LIBCMNDIR)/libhvcall/hvcall.in \
 	$(LIBCMNDIR)/libvirtio/virtio.in \
@@ -45,7 +48,9 @@  BOARD_SLOF_IN = \
 	$(LIBCMNDIR)/libveth/veth.in \
 	$(LIBCMNDIR)/libe1k/e1k.in \
 	$(LIBCMNDIR)/libnet/libnet.in \
-	$(LIBCMNDIR)/libbootmenu/bootmenu.in
+	$(LIBCMNDIR)/libbootmenu/bootmenu.in \
+	$(LIBCMNDIR)/libtpm/tpm.in
+
 BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code)
 
 include $(SLOFCMNDIR)/Makefile.inc
@@ -83,6 +88,7 @@  VIO_FFS_FILES = \
 	$(SLOFBRDDIR)/pci-device_1af4_1050.fs \
 	$(SLOFBRDDIR)/vio-hvterm.fs \
 	$(SLOFBRDDIR)/vio-vscsi.fs \
+	$(SLOFBRDDIR)/vio-vtpm-cdriver.fs \
 	$(SLOFBRDDIR)/vio-veth.fs \
 	$(SLOFBRDDIR)/rtas-nvram.fs \
 	$(SLOFBRDDIR)/virtio-net.fs \
@@ -114,6 +120,7 @@  OF_FFS_FILES = \
 	$(SLOFBRDDIR)/default-font.bin \
 	$(SLOFBRDDIR)/pci-phb.fs \
 	$(SLOFBRDDIR)/rtas.fs \
+	$(SLOFBRDDIR)/vtpm-sml.fs \
 	$(SLOFBRDDIR)/pci-device_1234_1111.fs \
 	$(SLOFBRDDIR)/pci-device_1013_00b8.fs \
 	$(SLOFBRDDIR)/pci-device_8086_100e.fs \
diff --git a/board-qemu/slof/tree.fs b/board-qemu/slof/tree.fs
index d95fde3..39dc6f6 100644
--- a/board-qemu/slof/tree.fs
+++ b/board-qemu/slof/tree.fs
@@ -87,6 +87,9 @@  include fbuffer.fs
 	    2dup " qemu,spapr-nvram" strequal IF
 	    	" rtas-nvram.fs" included
 	    THEN
+	    2dup " IBM,vtpm" strequal IF
+                " vio-vtpm-cdriver.fs" included
+	    THEN
             2drop
        THEN
        peer
diff --git a/board-qemu/slof/vio-vtpm-cdriver.fs b/board-qemu/slof/vio-vtpm-cdriver.fs
new file mode 100644
index 0000000..f873456
--- /dev/null
+++ b/board-qemu/slof/vio-vtpm-cdriver.fs
@@ -0,0 +1,72 @@ 
+\ *****************************************************************************
+\ * Copyright (c) 2015 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+." Populating " pwd
+
+false VALUE vtpm-debug?
+0     VALUE vtpm-unit
+
+: setup-alias
+    " ibm,vtpm" find-alias 0= IF
+        " ibm,vtpm" get-node node>path set-alias
+    ELSE
+        drop
+    THEN
+;
+
+: vtpm-cleanup ( )
+    vtpm-debug? IF ." VTPM: Disabling RTAS bypass" cr THEN
+    tpm-finalize
+    vtpm-unit 0 rtas-set-tce-bypass
+;
+
+: vtpm-init ( -- true | false )
+    0 0 get-node open-node ?dup 0= IF EXIT THEN
+    my-self >r
+    dup to my-self
+
+    vtpm-debug? IF ." VTPM: Initializing for c-driver" cr THEN
+
+    my-unit to vtpm-unit
+
+    \ Enable TCE bypass special qemu feature
+    vtpm-unit 1 rtas-set-tce-bypass
+
+    \ Have TCE bypass cleaned up
+    ['] vtpm-cleanup add-quiesce-xt
+
+    tpm-start dup 0= IF
+        vtpm-debug? IF ." VTPM: Success from tpm-start" cr THEN
+        drop
+        setup-alias
+    ELSE
+        ." VTPM: Error code from tpm-start: " . cr
+    THEN
+
+    close-node
+    r> to my-self
+;
+
+: open ( )
+    vtpm-debug? IF ." VTPM: vTPM open()" cr THEN
+    true
+;
+
+: close ( )
+    vtpm-debug? IF ." VTPM: vTPM close()" cr THEN
+;
+
+\ setup alias and the RTAS bypass
+vtpm-init
+
+\ setup the log
+include vtpm-sml.fs
diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs
new file mode 100644
index 0000000..7cd3729
--- /dev/null
+++ b/board-qemu/slof/vtpm-sml.fs
@@ -0,0 +1,62 @@ 
+\ *****************************************************************************
+\ * Copyright (c) 2015 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ KVM/qemu TPM Stored Measurement Log (SML) entries in /ibm,vtpm
+
+" /" find-device
+
+new-device
+
+false VALUE    vtpm-debug?
+0     VALUE    log-base
+40000 CONSTANT LOG-SIZE   \ 256k per VTPM FW spec.
+
+LOG-SIZE BUFFER: log-base
+
+\ create /ibm,vtpm
+s" ibm,vtpm" 2dup device-name device-type
+
+: sml-get-allocated-size ( -- buffer-size)
+    vtpm-debug? IF
+        ." Call to sml-get-allocated-size; size = 0x" LOG-SIZE . cr
+    THEN
+    LOG-SIZE
+;
+
+: sml-handover ( dest size -- )
+    vtpm-debug? IF
+        2dup
+        ." Call to sml-handover; size = 0x" . ." dest = " . cr
+    THEN
+    log-base        ( dest size src )
+    -rot            ( src dest size )
+    move
+;
+
+\
+\ internal API calls
+\
+
+: unassert-physical-presence ( -- )
+    tpm-unassert-physical-presence                    ( errcode )
+    dup 0<> IF
+        ." VTPM: Error code from tpm-unassert-physical-presence: " . cr
+    ELSE
+        drop
+    THEN
+;
+
+: open  true ;
+: close ;
+
+finish-device
+device-end
diff --git a/lib/Makefile b/lib/Makefile
index 1e8bb62..7369894 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -11,7 +11,7 @@ 
 # ****************************************************************************/
 
 SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \
-          libusb libveth libe1k libbcm libnet libbootmenu
+          libusb libveth libe1k libbcm libnet libbootmenu libtpm
 
 all:  subdirs
 
diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile
index ff19e1c..012fe37 100644
--- a/lib/libtpm/Makefile
+++ b/lib/libtpm/Makefile
@@ -23,7 +23,7 @@  TARGET = ../libtpm.a
 
 all: $(TARGET)
 
-SRCS = tpm_drivers.c
+SRCS = tpm_drivers.c tcgbios.c
 
 OBJS = $(SRCS:%.c=%.o)
 
diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c
new file mode 100644
index 0000000..5b12461
--- /dev/null
+++ b/lib/libtpm/tcgbios.c
@@ -0,0 +1,271 @@ 
+
+/*****************************************************************************
+ * Copyright (c) 2015 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ *  Implementation of the TPM BIOS extension according to the specification
+ *  described in the IBM VTPM Firmware document and the TCG Specification
+ *  that can be found here under the following link:
+ *  http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
+ */
+
+#include "types.h"
+#include "byteorder.h"
+#include "tpm_drivers.h"
+#include "string.h"
+#include "tcgbios.h"
+#include "tcgbios_int.h"
+#include "stdio.h"
+
+#undef TCGBIOS_DEBUG
+//#define TCGBIOS_DEBUG
+#ifdef TCGBIOS_DEBUG
+#define dprintf(_x ...) do { printf("TCGBIOS: " _x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+struct tpm_state {
+	unsigned tpm_probed:1;
+	unsigned tpm_found:1;
+	unsigned tpm_working:1;
+	unsigned has_physical_presence:1;
+};
+
+static struct tpm_state tpm_state;
+
+/********************************************************
+  Extensions for TCG-enabled BIOS
+ *******************************************************/
+
+static void probe_tpm(void)
+{
+	tpm_state.tpm_probed = true;
+	tpm_state.tpm_found = spapr_is_vtpm_present();
+	tpm_state.tpm_working = tpm_state.tpm_found;
+}
+
+/****************************************************************
+ * TPM hardware command wrappers
+ ****************************************************************/
+
+/* Helper function for sending TPM commands that take a single
+ * optional parameter (0, 1, or 2 bytes) and have no special response.
+ */
+static int
+tpm_simple_cmd(uint8_t locty, uint32_t ordinal, int param_size, uint16_t param,
+	       enum tpm_duration_type to_t)
+{
+	struct {
+		struct tpm_req_header trqh;
+		uint16_t param;
+	} __attribute__((packed)) req = {
+		.trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size),
+		.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
+		.trqh.ordinal = cpu_to_be32(ordinal),
+	};
+	uint8_t obuffer[64];
+	struct tpm_rsp_header *trsh = (void *)obuffer;
+	uint32_t obuffer_len = sizeof(obuffer);
+	int ret;
+
+	switch (param_size) {
+	case 2:
+		req.param = cpu_to_be16(param);
+		break;
+	case 1:
+		*(uint8_t *)&req.param = param;
+		break;
+	}
+
+	memset(obuffer, 0, sizeof(obuffer));
+	ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
+	ret = ret ? -1 : be32_to_cpu(trsh->errcode);
+	dprintf("Return from tpm_simple_cmd(%x, %x) = %x\n",
+		ordinal, param, ret);
+
+	return ret;
+}
+
+static int tpm12_get_capability(uint32_t cap, uint32_t subcap,
+			  struct tpm_rsp_header *rsp, uint32_t rsize)
+{
+	struct tpm_req_getcap trgc = {
+		.hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
+		.hdr.totlen = cpu_to_be32(sizeof(trgc)),
+		.hdr.ordinal = cpu_to_be32(TPM_ORD_GET_CAPABILITY),
+		.capArea = cpu_to_be32(cap),
+		.subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
+		.subCap = cpu_to_be32(subcap)
+	};
+	uint32_t resp_size = rsize;
+	int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
+				 TPM_DURATION_TYPE_SHORT);
+	ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
+	dprintf("TCGBIOS: Return code from TPM_GetCapability(%d, %d) = %x\n",
+		cap, subcap, ret);
+	return ret;
+}
+
+static int tpm12_read_permanent_flags(char *buf, size_t buf_len)
+{
+	struct tpm_rsp_getcap_perm_flags pf;
+	int ret;
+
+	memset(buf, 0, buf_len);
+	ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT,
+				   &pf.hdr, sizeof(pf));
+	if (ret)
+		return -1;
+
+	memcpy(buf, &pf.perm_flags, buf_len);
+
+	return 0;
+}
+
+static int tpm12_determine_timeouts(void)
+{
+	struct tpm_rsp_getcap_durations durations;
+	int i;
+	int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION,
+				       &durations.hdr, sizeof(durations));
+
+	if (ret)
+		return ret;
+
+	for (i = 0; i < TPM_NUM_DURATIONS; i++)
+		durations.durations[i] = be32_to_cpu(durations.durations[i]);
+
+	dprintf("durations: %u %u %u\n",
+		durations.durations[0],
+		durations.durations[1],
+		durations.durations[2]);
+
+	spapr_vtpm_set_durations(durations.durations);
+
+	return 0;
+}
+
+/****************************************************************
+ * Setup and Measurements
+ ****************************************************************/
+
+static bool tpm_is_working(void)
+{
+	if (!tpm_state.tpm_probed)
+		probe_tpm();
+
+	return tpm_state.tpm_working;
+}
+
+static void tpm_set_failure(void)
+{
+	/* we will try to deactivate the TPM now - ignoring all errors */
+	tpm_simple_cmd(0, TPM_ORD_SET_TEMP_DEACTIVATED,
+		       0, 0, TPM_DURATION_TYPE_SHORT);
+
+	tpm_state.tpm_working = false;
+}
+
+static int tpm12_assert_physical_presence(void)
+{
+	struct tpm_permanent_flags pf;
+	int ret = tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE,
+				 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
+	if (!ret)
+		return 0;
+
+	ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
+	if (ret)
+		return -1;
+
+	/* check if hardware physical presence is supported */
+	if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
+		/* HW. phys. presence may not be asserted ... */
+		return 0;
+	}
+
+	if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
+	   && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
+		tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE,
+			       2, TPM_PP_CMD_ENABLE, TPM_DURATION_TYPE_SHORT);
+		return tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE,
+				      2, TPM_PP_PRESENT,
+				      TPM_DURATION_TYPE_SHORT);
+	}
+	return -1;
+}
+
+static int tpm12_startup(void)
+{
+	dprintf("Starting with TPM_Startup(ST_CLEAR)\n");
+	int ret = tpm_simple_cmd(0, TPM_ORD_STARTUP,
+				 2, TPM_ST_CLEAR, TPM_DURATION_TYPE_SHORT);
+	if (ret)
+		goto err_exit;
+
+	/* asssertion of physical presence is only possible after startup */
+	ret = tpm12_assert_physical_presence();
+	if (!ret)
+		tpm_state.has_physical_presence = true;
+
+	ret = tpm12_determine_timeouts();
+	if (ret)
+		goto err_exit;
+
+	ret = tpm_simple_cmd(0, TPM_ORD_SELF_TEST_FULL,
+			     0, 0, TPM_DURATION_TYPE_LONG);
+	if (ret)
+		goto err_exit;
+
+	return 0;
+
+err_exit:
+	dprintf("TPM malfunctioning (line %d).\n", __LINE__);
+
+	tpm_set_failure();
+	return -1;
+}
+
+uint32_t tpm_start(void)
+{
+	tpm_state.has_physical_presence = false;
+
+	probe_tpm();
+
+	if (!tpm_is_working()) {
+		dprintf("%s: Machine does not have a working TPM\n",
+			__func__);
+		return TCGBIOS_FATAL_COM_ERROR;
+	}
+
+	return tpm12_startup();
+}
+
+void tpm_finalize(void)
+{
+	spapr_vtpm_finalize();
+}
+
+/*
+ * Give up physical presence; this function has to be called before
+ * the firmware transitions to the boot loader.
+ */
+uint32_t tpm_unassert_physical_presence(void)
+{
+	if (tpm_state.has_physical_presence)
+		tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE,
+			       2, TPM_PP_NOT_PRESENT_LOCK,
+			       TPM_DURATION_TYPE_SHORT);
+
+	return 0;
+}
diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h
new file mode 100644
index 0000000..5b5e481
--- /dev/null
+++ b/lib/libtpm/tcgbios.h
@@ -0,0 +1,22 @@ 
+/*****************************************************************************
+ * Copyright (c) 2015 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef TCGBIOS_H
+#define TCGBIOS_H
+
+#include <stdint.h>
+
+uint32_t tpm_start(void);
+void tpm_finalize(void);
+uint32_t tpm_unassert_physical_presence(void);
+
+#endif /* TCGBIOS_H */
diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h
new file mode 100644
index 0000000..11f91a7
--- /dev/null
+++ b/lib/libtpm/tcgbios_int.h
@@ -0,0 +1,153 @@ 
+/*****************************************************************************
+ * Copyright (c) 2015 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef TCGBIOS_INT_H
+#define TCGBIOS_INT_H
+
+#include <stdint.h>
+
+#include "tpm_drivers.h"
+
+/* internal error codes */
+#define TCGBIOS_OK                       0x0
+#define TCGBIOS_LOGOVERFLOW              0x1
+#define TCGBIOS_GENERAL_ERROR            0x2
+#define TCGBIOS_FIRMWARE_ERROR           0x3
+#define TCGBIOS_FATAL_COM_ERROR          0x4
+#define TCGBIOS_INVALID_INPUT_PARA       0x5
+#define TCGBIOS_COMMAND_ERROR            0x6
+#define TCGBIOS_INTERFACE_SHUTDOWN       0x7
+
+#define TPM_ORD_SELF_TEST_FULL           0x00000050
+#define TPM_ORD_FORCE_CLEAR              0x0000005d
+#define TPM_ORD_GET_CAPABILITY           0x00000065
+#define TPM_ORD_PHYSICAL_ENABLE          0x0000006f
+#define TPM_ORD_PHYSICAL_DISABLE         0x00000070
+#define TPM_ORD_SET_OWNER_INSTALL        0x00000071
+#define TPM_ORD_PHYSICAL_SET_DEACTIVATED 0x00000072
+#define TPM_ORD_SET_TEMP_DEACTIVATED     0x00000073
+#define TPM_ORD_STARTUP                  0x00000099
+#define TPM_ORD_PHYSICAL_PRESENCE        0x4000000a
+#define TPM_ORD_EXTEND                   0x00000014
+
+#define TPM_ST_CLEAR                     0x1
+#define TPM_ST_STATE                     0x2
+#define TPM_ST_DEACTIVATED               0x3
+
+#define TPM_PP_CMD_ENABLE                0x0020
+#define TPM_PP_PRESENT                   0x0008
+#define TPM_PP_NOT_PRESENT_LOCK          0x0014
+
+#define TPM_TAG_RQU_CMD                  0x00c1
+
+/* TPM command error codes */
+#define TPM_INVALID_POSTINIT             0x26
+
+/* event types */
+#define EV_POST_CODE                     1
+#define EV_SEPARATOR                     4
+#define EV_ACTION                        5
+#define EV_EVENT_TAG                     6
+#define EV_IPL                          13
+#define EV_IPL_PARTITION_DATA           14
+
+#define SHA1_BUFSIZE                    20
+
+/* Input and Output blocks for the TCG BIOS commands */
+
+/* PCClient_PCREventStruct -- format of log entries; compatible with x86 */
+struct pcpes {
+	uint32_t pcrindex;
+	uint32_t eventtype;
+	uint8_t digest[SHA1_BUFSIZE];
+	uint32_t eventdatasize;
+	uint32_t event;
+} __attribute__((packed));
+
+struct tpm_req_header {
+	uint16_t tag;
+	uint32_t totlen;
+	uint32_t ordinal;
+} __attribute__((packed));
+
+#define TPM_REQ_HEADER_SIZE (sizeof(struct tpm_req_header))
+
+struct tpm_rsp_header {
+	uint16_t tag;
+	uint32_t totlen;
+	uint32_t errcode;
+} __attribute__((packed));
+
+#define TPM_RSP_HEADER_SIZE (sizeof(struct tpm_rsp_header))
+
+struct tpm_req_extend {
+	struct tpm_req_header hdr;
+	uint32_t pcrindex;
+	uint8_t digest[SHA1_BUFSIZE];
+} __attribute__((packed));
+
+struct tpm_rsp_extend {
+	struct tpm_rsp_header hdr;
+	uint8_t digest[SHA1_BUFSIZE];
+} __attribute__((packed));
+
+struct tpm_req_getcap {
+	struct tpm_req_header hdr;
+	uint32_t capArea;
+	uint32_t subCapSize;
+	uint32_t subCap;
+} __attribute__((packed));
+
+#define TPM_CAP_FLAG      0x04
+#define TPM_CAP_PROPERTY  0x05
+#define TPM_CAP_FLAG_PERMANENT  0x108
+#define TPM_CAP_PROP_DURATION   0x120
+
+struct tpm_req_getcap_perm_flags {
+	struct tpm_req_header hdr;
+	uint32_t cap_area;
+	uint32_t sub_cap_zize;
+	uint32_t sub_cap;
+} __attribute__((packed));
+
+struct tpm_permanent_flags {
+	uint16_t tag;
+	uint8_t flags[20];
+} __attribute__((packed));
+
+#define PERM_FLAG_IDX_DISABLE 0
+#define PERM_FLAG_IDX_OWNERSHIP 1
+#define PERM_FLAG_IDX_DEACTIVATED 2
+#define PERM_FLAG_IDX_DISABLEOWNERCLEAR 4
+#define PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK 6
+#define PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE 7
+#define PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE 8
+
+struct tpm_rsp_getcap_perm_flags {
+	struct tpm_rsp_header hdr;
+	uint32_t size;
+	struct tpm_permanent_flags perm_flags;
+} __attribute__((packed));
+
+struct tpm_rsp_getcap_ownerauth {
+	struct tpm_rsp_header hdr;
+	uint32_t size;
+	uint8_t flag;
+} __attribute__((packed));
+
+struct tpm_rsp_getcap_durations {
+	struct tpm_rsp_header hdr;
+	uint32_t size;
+	uint32_t durations[TPM_NUM_DURATIONS];
+} __attribute__((packed));
+
+#endif /* TCGBIOS_INT_H */
diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code
new file mode 100644
index 0000000..08f52e9
--- /dev/null
+++ b/lib/libtpm/tpm.code
@@ -0,0 +1,46 @@ 
+/******************************************************************************
+ * Copyright (c) 2015 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * libtpm bindings for SLOF - implementation
+ */
+
+#include <tcgbios.h>
+
+
+/************************************************/
+/* Startup TPM code                             */
+/* SLOF:   tpm-start  ( -- errcode )            */
+/* LIBTPM: tpm_start(void)                      */
+/************************************************/
+PRIM(tpm_X2d_start)
+	PUSH;
+	TOS.n = tpm_start();
+MIRP
+
+/************************************************/
+/* Shutdown TPM layer before OS takes over      */
+/* SLOF:   tpm-finalize  ( -- )                 */
+/* LIBTPM: tpm_finalize(void)                   */
+/************************************************/
+PRIM(tpm_X2d_finalize)
+	tpm_finalize();
+MIRP
+
+/***************************************************************/
+/* Prepare TPM state for bootloader                            */
+/* SLOF:   tpm-unassert-physical-presence ( -- errcode )       */
+/* LIBTPM: tpm_unassert_physical-presence(void)                */
+/***************************************************************/
+PRIM(tpm_X2d_unassert_X2d_physical_X2d_presence)
+	PUSH;
+	TOS.n = tpm_unassert_physical_presence();
+MIRP
diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in
new file mode 100644
index 0000000..e212483
--- /dev/null
+++ b/lib/libtpm/tpm.in
@@ -0,0 +1,18 @@ 
+/******************************************************************************
+ * Copyright (c) 2015 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * libtpm bindings for SLOF - definitions
+ */
+
+cod(tpm-start)
+cod(tpm-finalize)
+cod(tpm-unassert-physical-presence)
diff --git a/lib/libtpm/tpm_drivers.c b/lib/libtpm/tpm_drivers.c
index 19e988d..7b1c9c8 100644
--- a/lib/libtpm/tpm_drivers.c
+++ b/lib/libtpm/tpm_drivers.c
@@ -20,6 +20,7 @@ 
 #include "tpm_drivers.h"
 #include "libhvcall.h"
 #include "paflof.h"
+#include "tcgbios_int.h"
 
 #undef PAPR_VTPM_DEBUG
 //#define PAPR_VTPM_DEBUG
@@ -476,3 +477,15 @@  bool spapr_is_vtpm_present(void)
 
 	return rc;
 }
+
+int tpmhw_transmit(uint8_t locty, struct tpm_req_header *req,
+                   void *respbuffer, uint32_t *respbufferlen,
+                   enum tpm_duration_type to_t)
+{
+        if (!spapr_vtpm_senddata((uint8_t *)req, be32_to_cpu(req->totlen)) ||
+            !spapr_vtpm_waitresponseready(to_t) ||
+            !spapr_vtpm_readresponse(respbuffer, respbufferlen) ||
+            *respbufferlen < sizeof(struct tpm_rsp_header))
+                return -1;
+        return 0;
+}
diff --git a/lib/libtpm/tpm_drivers.h b/lib/libtpm/tpm_drivers.h
index 5d19514..ab2e152 100644
--- a/lib/libtpm/tpm_drivers.h
+++ b/lib/libtpm/tpm_drivers.h
@@ -78,4 +78,9 @@  uint32_t spapr_vtpm_get_buffersize(void);
 vtpm_drv_state spapr_vtpm_get_state(void);
 vtpm_drv_error spapr_vtpm_get_error(void);
 
+struct tpm_req_header;
+int tpmhw_transmit(uint8_t locty, struct tpm_req_header *req,
+                   void *respbuffer, uint32_t *respbufferlen,
+                   enum tpm_duration_type to_t);
+
 #endif /* TPM_DRIVERS_H */
diff --git a/slof/fs/start-up.fs b/slof/fs/start-up.fs
index 7020f5c..0715357 100644
--- a/slof/fs/start-up.fs
+++ b/slof/fs/start-up.fs
@@ -56,6 +56,13 @@ 
 ;
 
 : (boot?) ( -- )
+   \ last step before we boot we give up physical presence on the TPM
+   s" /ibm,vtpm" find-node dup IF
+      s" unassert-physical-presence" rot $call-static
+   ELSE
+      drop
+   THEN
+
    of-prompt? not auto-boot? and IF
       (boot)
    THEN