From Andreas Niederl's original posting with adaptations where necessary:
This patch is based of off version 9 of Stefan Berger's patch series
"Qemu Trusted Platform Module (TPM) integration"
and adds a new backend driver for it.
This patch adds a passthrough backend driver for passing commands sent to the
emulated TPM device directly to a TPM device opened on the host machine.
Thus it is possible to use a hardware TPM device in a system running on QEMU,
providing the ability to access a TPM in a special state (e.g. after a Trusted
Boot).
This functionality is being used in the acTvSM Trusted Virtualization Platform
which is available on [1].
Usage example:
qemu-system-x86_64 -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \
-device tpm-tis,tpmdev=tpm0 \
-cdrom test.iso -boot d
Some notes about the host TPM:
The TPM needs to be enabled and activated. If that's not the case one
has to go through the BIOS/UEFI and enable and activate that TPM for TPM
commands to work as expected.
It may be necessary to boot the kernel using tpm_tis.force=1 in the boot
command line or 'modprobe tpm_tis force=1' in case of using it as a module.
Regards,
Andreas Niederl, Stefan Berger
[1] http://trustedjava.sourceforge.net/
Signed-off-by: Andreas Niederl<address@hidden>
Signed-off-by: Stefan Berger<address@hidden>
---
Changes for v12:
- check size indicator in response from TPM to match that of the received
packet
Changes for v10:
- clarified documentation
- using /dev/tpm0 as default device if path option is not given
- refactored code handling 'device' option into its own function
- fixed name of structure to TPMPassthruThreadParams
- only add tpm_passthrough_driver to collection of backends if
it is compiled on the host
Changes for v9:
- prefixing of all functions and variables with tpm_passthrough_
- cleanup of all variables into a structure that is now accessed
using TPMBackend (tb->s.tpm_pt)
- build it on Linux machines
- added function to test whether given device is a TPM and refuse
startup if it is not
---
Makefile.target | 1 +
configure | 3 +
hw/tpm_passthrough.c | 477 ++++++++++++++++++++++++++++++++++++++++++++++++++
qemu-options.hx | 33 ++++
tpm.c | 23 +++
tpm.h | 34 ++++
6 files changed, 571 insertions(+), 0 deletions(-)
create mode 100644 hw/tpm_passthrough.c
diff --git a/Makefile.target b/Makefile.target
index 37d5d10..4fc96e6 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -206,6 +206,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += memory.o
obj-$(CONFIG_TPM) += tpm.o tpm_tis.o
+obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
LIBS+=-lz
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
diff --git a/configure b/configure
index 385feb4..25995bc 100755
--- a/configure
+++ b/configure
@@ -3721,6 +3721,9 @@ fi
if test "$tpm" = "yes"; then
if test "$target_softmmu" = "yes" ; then
+ if test "$linux" = "yes" ; then
+ echo "CONFIG_TPM_PASSTHROUGH=y">> $config_target_mak
+ fi
echo "CONFIG_TPM=y">> $config_host_mak
fi
fi
diff --git a/hw/tpm_passthrough.c b/hw/tpm_passthrough.c
new file mode 100644
index 0000000..f9cfe3d
--- /dev/null
+++ b/hw/tpm_passthrough.c
@@ -0,0 +1,477 @@
+/*
+ * passthrough TPM driver
+ *
+ * Copyright (c) 2010, 2011 IBM Corporation
+ * Authors:
+ * Stefan Berger<address@hidden>
+ *
+ * Copyright (C) 2011 IAIK, Graz University of Technology
+ * Author: Andreas Niederl
+ *
+ * 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, see<http://www.gnu.org/licenses/>
+ */
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "tpm.h"
+#include "hw/hw.h"
+#include "hw/tpm_tis.h"
+#include "hw/pc.h"
+
+/* #define DEBUG_TPM */
+
+/* data structures */
+
+typedef struct TPMPassthruThreadParams {
+ TPMState *tpm_state;
+
+ TPMRecvDataCB *recv_data_callback;
+ TPMBackend *tb;
+} TPMPassthruThreadParams;
+
+struct TPMPassthruState {
+ QemuThread thread;
+ bool thread_terminate;
+ bool thread_running;
+
+ TPMPassthruThreadParams tpm_thread_params;
+
+ char tpm_dev[64];
+ int tpm_fd;
+ bool had_startup_error;
+};
+
+#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
+
+/* borrowed from qemu-char.c */
+static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
+{
+ int ret, len1;
+
+ len1 = len;
+ while (len1> 0) {
+ ret = write(fd, buf, len1);
+ if (ret< 0) {
+ if (errno != EINTR&& errno != EAGAIN) {
+ return -1;
+ }
+ } else if (ret == 0) {
+ break;
+ } else {
+ buf += ret;
+ len1 -= ret;
+ }
+ }
+ return len - len1;
+}
+
+static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
+{
+ int ret, len1;
+ uint8_t *buf1;
+
+ len1 = len;
+ buf1 = buf;
+ while ((len1> 0)&& (ret = read(fd, buf1, len1)) != 0) {
+ if (ret< 0) {
+ if (errno != EINTR&& errno != EAGAIN) {
+ return -1;
+ }
+ } else {
+ buf1 += ret;
+ len1 -= ret;
+ }
+ }
+ return len - len1;
+}
+
+static void *tpm_passthrough_main_loop(void *d)
+{
+ TPMPassthruThreadParams *thr_parms = d;
+ TPMPassthruState *tpm_pt = thr_parms->tb->s.tpm_pt;
+ uint32_t in_len, out_len;
+ uint8_t *in, *out;
+ uint8_t locty;
+ TPMLocality *cmd_locty;
+ int ret;