tpm: Move backend code under the 'backends/' directory
authorPhilippe Mathieu-Daudé <philmd@redhat.com>
Fri, 12 Jun 2020 08:54:44 +0000 (10:54 +0200)
committerStefan Berger <stefanb@linux.vnet.ibm.com>
Fri, 19 Jun 2020 11:25:55 +0000 (07:25 -0400)
TPM subsytem is split into backends (see commit f4ede81eed2)
and frontends (see i.e. 3676bc69b35). Keep the emulated
hardware 'frontends' under hw/tpm/, but move the backends
in the backends/tpm/ directory.

Suggested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20200612085444.8362-13-philmd@redhat.com
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
21 files changed:
Makefile
Makefile.objs
backends/Kconfig [new file with mode: 0644]
backends/tpm/Kconfig [new file with mode: 0644]
backends/tpm/Makefile.objs
backends/tpm/tpm_emulator.c [new file with mode: 0644]
backends/tpm/tpm_int.h [new file with mode: 0644]
backends/tpm/tpm_ioctl.h [new file with mode: 0644]
backends/tpm/tpm_passthrough.c [new file with mode: 0644]
backends/tpm/tpm_util.c [new file with mode: 0644]
backends/tpm/trace-events [new file with mode: 0644]
docs/specs/tpm.rst
hw/tpm/Kconfig
hw/tpm/Makefile.objs
hw/tpm/tpm_emulator.c [deleted file]
hw/tpm/tpm_int.h [deleted file]
hw/tpm/tpm_ioctl.h [deleted file]
hw/tpm/tpm_passthrough.c [deleted file]
hw/tpm/tpm_util.c [deleted file]
hw/tpm/trace-events
tests/qtest/tpm-emu.c

index 48f23aa97861d7f39083c2026906fa91fefd6a6a..a0092153af374a68761d1af64556ad2822fd45ab 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -418,7 +418,7 @@ MINIKCONF_ARGS = \
     CONFIG_LINUX=$(CONFIG_LINUX) \
     CONFIG_PVRDMA=$(CONFIG_PVRDMA)
 
-MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig
+MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/backends/Kconfig $(SRC_PATH)/hw/Kconfig
 MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig)
 MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
 
index 7ce2588b89a3f00046174d0b4b8e0391a6f35fb7..98383972eef3d8ece60496f6f3701aea71ef84fb 100644 (file)
@@ -125,6 +125,7 @@ trace-events-subdirs =
 trace-events-subdirs += accel/kvm
 trace-events-subdirs += accel/tcg
 trace-events-subdirs += backends
+trace-events-subdirs += backends/tpm
 trace-events-subdirs += crypto
 trace-events-subdirs += monitor
 ifeq ($(CONFIG_USER_ONLY),y)
diff --git a/backends/Kconfig b/backends/Kconfig
new file mode 100644 (file)
index 0000000..f35abc1
--- /dev/null
@@ -0,0 +1 @@
+source tpm/Kconfig
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
new file mode 100644 (file)
index 0000000..5d91eb8
--- /dev/null
@@ -0,0 +1,14 @@
+config TPM_BACKEND
+    bool
+    depends on TPM
+
+config TPM_PASSTHROUGH
+    bool
+    default y
+    # FIXME: should check for x86 host as well
+    depends on TPM_BACKEND && LINUX
+
+config TPM_EMULATOR
+    bool
+    default y
+    depends on TPM_BACKEND
index 8cf5772824ded1959aaafa8fbaf7b8fe4ec2bd04..db2731f634f6d12fb62dd90f003364d759efbb5d 100644 (file)
@@ -1 +1,4 @@
 common-obj-y += tpm_backend.o
+common-obj-y += tpm_util.o
+common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
+common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
new file mode 100644 (file)
index 0000000..9605339
--- /dev/null
@@ -0,0 +1,997 @@
+/*
+ *  Emulator TPM driver
+ *
+ *  Copyright (c) 2017 Intel Corporation
+ *  Author: Amarnath Valluri <amarnath.valluri@intel.com>
+ *
+ *  Copyright (c) 2010 - 2013, 2018 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ *  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/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "qemu/sockets.h"
+#include "io/channel-socket.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+#include "tpm_int.h"
+#include "tpm_ioctl.h"
+#include "migration/blocker.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+#include "chardev/char-fe.h"
+#include "trace.h"
+
+#define TYPE_TPM_EMULATOR "tpm-emulator"
+#define TPM_EMULATOR(obj) \
+    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
+
+#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
+
+/* data structures */
+
+/* blobs from the TPM; part of VM state when migrating */
+typedef struct TPMBlobBuffers {
+    uint32_t permanent_flags;
+    TPMSizedBuffer permanent;
+
+    uint32_t volatil_flags;
+    TPMSizedBuffer volatil;
+
+    uint32_t savestate_flags;
+    TPMSizedBuffer savestate;
+} TPMBlobBuffers;
+
+typedef struct TPMEmulator {
+    TPMBackend parent;
+
+    TPMEmulatorOptions *options;
+    CharBackend ctrl_chr;
+    QIOChannel *data_ioc;
+    TPMVersion tpm_version;
+    ptm_cap caps; /* capabilities of the TPM */
+    uint8_t cur_locty_number; /* last set locality */
+    Error *migration_blocker;
+
+    QemuMutex mutex;
+
+    unsigned int established_flag:1;
+    unsigned int established_flag_cached:1;
+
+    TPMBlobBuffers state_blobs;
+} TPMEmulator;
+
+struct tpm_error {
+    uint32_t tpm_result;
+    const char *string;
+};
+
+static const struct tpm_error tpm_errors[] = {
+    /* TPM 1.2 error codes */
+    { TPM_BAD_PARAMETER   , "a parameter is bad" },
+    { TPM_FAIL            , "operation failed" },
+    { TPM_KEYNOTFOUND     , "key could not be found" },
+    { TPM_BAD_PARAM_SIZE  , "bad parameter size"},
+    { TPM_ENCRYPT_ERROR   , "encryption error" },
+    { TPM_DECRYPT_ERROR   , "decryption error" },
+    { TPM_BAD_KEY_PROPERTY, "bad key property" },
+    { TPM_BAD_MODE        , "bad (encryption) mode" },
+    { TPM_BAD_VERSION     , "bad version identifier" },
+    { TPM_BAD_LOCALITY    , "bad locality" },
+    /* TPM 2 error codes */
+    { TPM_RC_FAILURE     , "operation failed" },
+    { TPM_RC_LOCALITY    , "bad locality"     },
+    { TPM_RC_INSUFFICIENT, "insufficient amount of data" },
+};
+
+static const char *tpm_emulator_strerror(uint32_t tpm_result)
+{
+    size_t i;
+
+    for (i = 0; i < ARRAY_SIZE(tpm_errors); i++) {
+        if (tpm_errors[i].tpm_result == tpm_result) {
+            return tpm_errors[i].string;
+        }
+    }
+    return "";
+}
+
+static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
+                                size_t msg_len_in, size_t msg_len_out)
+{
+    CharBackend *dev = &tpm->ctrl_chr;
+    uint32_t cmd_no = cpu_to_be32(cmd);
+    ssize_t n = sizeof(uint32_t) + msg_len_in;
+    uint8_t *buf = NULL;
+    int ret = -1;
+
+    qemu_mutex_lock(&tpm->mutex);
+
+    buf = g_alloca(n);
+    memcpy(buf, &cmd_no, sizeof(cmd_no));
+    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
+
+    n = qemu_chr_fe_write_all(dev, buf, n);
+    if (n <= 0) {
+        goto end;
+    }
+
+    if (msg_len_out != 0) {
+        n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
+        if (n <= 0) {
+            goto end;
+        }
+    }
+
+    ret = 0;
+
+end:
+    qemu_mutex_unlock(&tpm->mutex);
+    return ret;
+}
+
+static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
+                                     const uint8_t *in, uint32_t in_len,
+                                     uint8_t *out, uint32_t out_len,
+                                     bool *selftest_done,
+                                     Error **errp)
+{
+    ssize_t ret;
+    bool is_selftest = false;
+
+    if (selftest_done) {
+        *selftest_done = false;
+        is_selftest = tpm_util_is_selftest(in, in_len);
+    }
+
+    ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp);
+    if (ret != 0) {
+        return -1;
+    }
+
+    ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out,
+              sizeof(struct tpm_resp_hdr), errp);
+    if (ret != 0) {
+        return -1;
+    }
+
+    ret = qio_channel_read_all(tpm_emu->data_ioc,
+              (char *)out + sizeof(struct tpm_resp_hdr),
+              tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp);
+    if (ret != 0) {
+        return -1;
+    }
+
+    if (is_selftest) {
+        *selftest_done = tpm_cmd_get_errcode(out) == 0;
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
+                                     Error **errp)
+{
+    ptm_loc loc;
+
+    if (tpm_emu->cur_locty_number == locty_number) {
+        return 0;
+    }
+
+    trace_tpm_emulator_set_locality(locty_number);
+
+    memset(&loc, 0, sizeof(loc));
+    loc.u.req.loc = locty_number;
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc,
+                             sizeof(loc), sizeof(loc)) < 0) {
+        error_setg(errp, "tpm-emulator: could not set locality : %s",
+                   strerror(errno));
+        return -1;
+    }
+
+    loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
+    if (loc.u.resp.tpm_result != 0) {
+        error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x",
+                   loc.u.resp.tpm_result);
+        return -1;
+    }
+
+    tpm_emu->cur_locty_number = locty_number;
+
+    return 0;
+}
+
+static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
+                                        Error **errp)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+    trace_tpm_emulator_handle_request();
+
+    if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 ||
+        tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len,
+                                  cmd->out, cmd->out_len,
+                                  &cmd->selftest_done, errp) < 0) {
+        tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
+    }
+}
+
+static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
+{
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY,
+                             &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
+        error_report("tpm-emulator: probing failed : %s", strerror(errno));
+        return -1;
+    }
+
+    tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
+
+    trace_tpm_emulator_probe_caps(tpm_emu->caps);
+
+    return 0;
+}
+
+static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
+{
+    ptm_cap caps = 0;
+    const char *tpm = NULL;
+
+    /* check for min. required capabilities */
+    switch (tpm_emu->tpm_version) {
+    case TPM_VERSION_1_2:
+        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+               PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP |
+               PTM_CAP_SET_BUFFERSIZE;
+        tpm = "1.2";
+        break;
+    case TPM_VERSION_2_0:
+        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
+               PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
+        tpm = "2";
+        break;
+    case TPM_VERSION_UNSPEC:
+        error_report("tpm-emulator: TPM version has not been set");
+        return -1;
+    }
+
+    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
+        error_report("tpm-emulator: TPM does not implement minimum set of "
+                     "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_stop_tpm(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_res res;
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
+        error_report("tpm-emulator: Could not stop TPM: %s",
+                     strerror(errno));
+        return -1;
+    }
+
+    res = be32_to_cpu(res);
+    if (res) {
+        error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x %s", res,
+                     tpm_emulator_strerror(res));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_set_buffer_size(TPMBackend *tb,
+                                        size_t wanted_size,
+                                        size_t *actual_size)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_setbuffersize psbs;
+
+    if (tpm_emulator_stop_tpm(tb) < 0) {
+        return -1;
+    }
+
+    psbs.u.req.buffersize = cpu_to_be32(wanted_size);
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
+                             sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
+        error_report("tpm-emulator: Could not set buffer size: %s",
+                     strerror(errno));
+        return -1;
+    }
+
+    psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result);
+    if (psbs.u.resp.tpm_result != 0) {
+        error_report("tpm-emulator: TPM result for set buffer size : 0x%x %s",
+                     psbs.u.resp.tpm_result,
+                     tpm_emulator_strerror(psbs.u.resp.tpm_result));
+        return -1;
+    }
+
+    if (actual_size) {
+        *actual_size = be32_to_cpu(psbs.u.resp.buffersize);
+    }
+
+    trace_tpm_emulator_set_buffer_size(
+            be32_to_cpu(psbs.u.resp.buffersize),
+            be32_to_cpu(psbs.u.resp.minsize),
+            be32_to_cpu(psbs.u.resp.maxsize));
+
+    return 0;
+}
+
+static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize,
+                                     bool is_resume)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_init init = {
+        .u.req.init_flags = 0,
+    };
+    ptm_res res;
+
+    trace_tpm_emulator_startup_tpm_resume(is_resume, buffersize);
+
+    if (buffersize != 0 &&
+        tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
+        goto err_exit;
+    }
+
+    if (is_resume) {
+        init.u.req.init_flags |= cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE);
+    }
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
+                             sizeof(init)) < 0) {
+        error_report("tpm-emulator: could not send INIT: %s",
+                     strerror(errno));
+        goto err_exit;
+    }
+
+    res = be32_to_cpu(init.u.resp.tpm_result);
+    if (res) {
+        error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x %s", res,
+                     tpm_emulator_strerror(res));
+        goto err_exit;
+    }
+    return 0;
+
+err_exit:
+    return -1;
+}
+
+static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
+{
+    return tpm_emulator_startup_tpm_resume(tb, buffersize, false);
+}
+
+static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_est est;
+
+    if (tpm_emu->established_flag_cached) {
+        return tpm_emu->established_flag;
+    }
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est,
+                             0, sizeof(est)) < 0) {
+        error_report("tpm-emulator: Could not get the TPM established flag: %s",
+                     strerror(errno));
+        return false;
+    }
+    trace_tpm_emulator_get_tpm_established_flag(est.u.resp.bit);
+
+    tpm_emu->established_flag_cached = 1;
+    tpm_emu->established_flag = (est.u.resp.bit != 0);
+
+    return tpm_emu->established_flag;
+}
+
+static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
+                                                   uint8_t locty)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_reset_est reset_est;
+    ptm_res res;
+
+    /* only a TPM 2.0 will support this */
+    if (tpm_emu->tpm_version != TPM_VERSION_2_0) {
+        return 0;
+    }
+
+    reset_est.u.req.loc = tpm_emu->cur_locty_number;
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED,
+                             &reset_est, sizeof(reset_est),
+                             sizeof(reset_est)) < 0) {
+        error_report("tpm-emulator: Could not reset the establishment bit: %s",
+                     strerror(errno));
+        return -1;
+    }
+
+    res = be32_to_cpu(reset_est.u.resp.tpm_result);
+    if (res) {
+        error_report(
+            "tpm-emulator: TPM result for rest established flag: 0x%x %s",
+            res, tpm_emulator_strerror(res));
+        return -1;
+    }
+
+    tpm_emu->established_flag_cached = 0;
+
+    return 0;
+}
+
+static void tpm_emulator_cancel_cmd(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_res res;
+
+    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) {
+        trace_tpm_emulator_cancel_cmd_not_supt();
+        return;
+    }
+
+    /* FIXME: make the function non-blocking, or it may block a VCPU */
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
+                             sizeof(res)) < 0) {
+        error_report("tpm-emulator: Could not cancel command: %s",
+                     strerror(errno));
+    } else if (res != 0) {
+        error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
+                     be32_to_cpu(res));
+    }
+}
+
+static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+    return tpm_emu->tpm_version;
+}
+
+static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
+{
+    size_t actual_size;
+
+    if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) {
+        return 4096;
+    }
+
+    return actual_size;
+}
+
+static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
+{
+    Error *err = NULL;
+    ptm_cap caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB |
+                   PTM_CAP_STOP;
+
+    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
+        error_setg(&tpm_emu->migration_blocker,
+                   "Migration disabled: TPM emulator does not support "
+                   "migration");
+        migrate_add_blocker(tpm_emu->migration_blocker, &err);
+        if (err) {
+            error_report_err(err);
+            error_free(tpm_emu->migration_blocker);
+            tpm_emu->migration_blocker = NULL;
+
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
+{
+    ptm_res res;
+    Error *err = NULL;
+    int fds[2] = { -1, -1 };
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
+        error_report("tpm-emulator: Failed to create socketpair");
+        return -1;
+    }
+
+    qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0,
+                             sizeof(res)) < 0 || res != 0) {
+        error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
+                     strerror(errno));
+        goto err_exit;
+    }
+
+    tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));
+    if (err) {
+        error_prepend(&err, "tpm-emulator: Failed to create io channel: ");
+        error_report_err(err);
+        goto err_exit;
+    }
+
+    closesocket(fds[1]);
+
+    return 0;
+
+err_exit:
+    closesocket(fds[0]);
+    closesocket(fds[1]);
+    return -1;
+}
+
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
+{
+    const char *value;
+
+    value = qemu_opt_get(opts, "chardev");
+    if (value) {
+        Error *err = NULL;
+        Chardev *dev = qemu_chr_find(value);
+
+        if (!dev) {
+            error_report("tpm-emulator: tpm chardev '%s' not found.", value);
+            goto err;
+        }
+
+        if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
+            error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
+                          value);
+            error_report_err(err);
+            goto err;
+        }
+
+        tpm_emu->options->chardev = g_strdup(value);
+    }
+
+    if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
+        goto err;
+    }
+
+    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
+     * by passthrough driver, which not yet using GIOChannel.
+     */
+    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
+                             &tpm_emu->tpm_version)) {
+        error_report("'%s' is not emulating TPM device. Error: %s",
+                      tpm_emu->options->chardev, strerror(errno));
+        goto err;
+    }
+
+    switch (tpm_emu->tpm_version) {
+    case TPM_VERSION_1_2:
+        trace_tpm_emulator_handle_device_opts_tpm12();
+        break;
+    case TPM_VERSION_2_0:
+        trace_tpm_emulator_handle_device_opts_tpm2();
+        break;
+    default:
+        trace_tpm_emulator_handle_device_opts_unspec();
+    }
+
+    if (tpm_emulator_probe_caps(tpm_emu) ||
+        tpm_emulator_check_caps(tpm_emu)) {
+        goto err;
+    }
+
+    return tpm_emulator_block_migration(tpm_emu);
+
+err:
+    trace_tpm_emulator_handle_device_opts_startup_error();
+
+    return -1;
+}
+
+static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+{
+    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
+
+    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
+        object_unref(OBJECT(tb));
+        return NULL;
+    }
+
+    return tb;
+}
+
+static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
+
+    options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
+    options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
+
+    return options;
+}
+
+static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {
+        .name = "chardev",
+        .type = QEMU_OPT_STRING,
+        .help = "Character device to use for out-of-band control messages",
+    },
+    { /* end of list */ },
+};
+
+/*
+ * Transfer a TPM state blob from the TPM into a provided buffer.
+ *
+ * @tpm_emu: TPMEmulator
+ * @type: the type of blob to transfer
+ * @tsb: the TPMSizeBuffer to fill with the blob
+ * @flags: the flags to return to the caller
+ */
+static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu,
+                                       uint8_t type,
+                                       TPMSizedBuffer *tsb,
+                                       uint32_t *flags)
+{
+    ptm_getstate pgs;
+    ptm_res res;
+    ssize_t n;
+    uint32_t totlength, length;
+
+    tpm_sized_buffer_reset(tsb);
+
+    pgs.u.req.state_flags = cpu_to_be32(PTM_STATE_FLAG_DECRYPTED);
+    pgs.u.req.type = cpu_to_be32(type);
+    pgs.u.req.offset = 0;
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB,
+                             &pgs, sizeof(pgs.u.req),
+                             offsetof(ptm_getstate, u.resp.data)) < 0) {
+        error_report("tpm-emulator: could not get state blob type %d : %s",
+                     type, strerror(errno));
+        return -1;
+    }
+
+    res = be32_to_cpu(pgs.u.resp.tpm_result);
+    if (res != 0 && (res & 0x800) == 0) {
+        error_report("tpm-emulator: Getting the stateblob (type %d) failed "
+                     "with a TPM error 0x%x %s", type, res,
+                     tpm_emulator_strerror(res));
+        return -1;
+    }
+
+    totlength = be32_to_cpu(pgs.u.resp.totlength);
+    length = be32_to_cpu(pgs.u.resp.length);
+    if (totlength != length) {
+        error_report("tpm-emulator: Expecting to read %u bytes "
+                     "but would get %u", totlength, length);
+        return -1;
+    }
+
+    *flags = be32_to_cpu(pgs.u.resp.state_flags);
+
+    if (totlength > 0) {
+        tsb->buffer = g_try_malloc(totlength);
+        if (!tsb->buffer) {
+            error_report("tpm-emulator: Out of memory allocating %u bytes",
+                         totlength);
+            return -1;
+        }
+
+        n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, tsb->buffer, totlength);
+        if (n != totlength) {
+            error_report("tpm-emulator: Could not read stateblob (type %d); "
+                         "expected %u bytes, got %zd",
+                         type, totlength, n);
+            return -1;
+        }
+    }
+    tsb->size = totlength;
+
+    trace_tpm_emulator_get_state_blob(type, tsb->size, *flags);
+
+    return 0;
+}
+
+static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu)
+{
+    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+    if (tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
+                                    &state_blobs->permanent,
+                                    &state_blobs->permanent_flags) < 0 ||
+        tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
+                                    &state_blobs->volatil,
+                                    &state_blobs->volatil_flags) < 0 ||
+        tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
+                                    &state_blobs->savestate,
+                                    &state_blobs->savestate_flags) < 0) {
+        goto err_exit;
+    }
+
+    return 0;
+
+ err_exit:
+    tpm_sized_buffer_reset(&state_blobs->volatil);
+    tpm_sized_buffer_reset(&state_blobs->permanent);
+    tpm_sized_buffer_reset(&state_blobs->savestate);
+
+    return -1;
+}
+
+/*
+ * Transfer a TPM state blob to the TPM emulator.
+ *
+ * @tpm_emu: TPMEmulator
+ * @type: the type of TPM state blob to transfer
+ * @tsb: TPMSizedBuffer containing the TPM state blob
+ * @flags: Flags describing the (encryption) state of the TPM state blob
+ */
+static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
+                                       uint32_t type,
+                                       TPMSizedBuffer *tsb,
+                                       uint32_t flags)
+{
+    ssize_t n;
+    ptm_setstate pss;
+    ptm_res tpm_result;
+
+    if (tsb->size == 0) {
+        return 0;
+    }
+
+    pss = (ptm_setstate) {
+        .u.req.state_flags = cpu_to_be32(flags),
+        .u.req.type = cpu_to_be32(type),
+        .u.req.length = cpu_to_be32(tsb->size),
+    };
+
+    /* write the header only */
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss,
+                             offsetof(ptm_setstate, u.req.data), 0) < 0) {
+        error_report("tpm-emulator: could not set state blob type %d : %s",
+                     type, strerror(errno));
+        return -1;
+    }
+
+    /* now the body */
+    n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size);
+    if (n != tsb->size) {
+        error_report("tpm-emulator: Writing the stateblob (type %d) "
+                     "failed; could not write %u bytes, but only %zd",
+                     type, tsb->size, n);
+        return -1;
+    }
+
+    /* now get the result */
+    n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr,
+                             (uint8_t *)&pss, sizeof(pss.u.resp));
+    if (n != sizeof(pss.u.resp)) {
+        error_report("tpm-emulator: Reading response from writing stateblob "
+                     "(type %d) failed; expected %zu bytes, got %zd", type,
+                     sizeof(pss.u.resp), n);
+        return -1;
+    }
+
+    tpm_result = be32_to_cpu(pss.u.resp.tpm_result);
+    if (tpm_result != 0) {
+        error_report("tpm-emulator: Setting the stateblob (type %d) failed "
+                     "with a TPM error 0x%x %s", type, tpm_result,
+                     tpm_emulator_strerror(tpm_result));
+        return -1;
+    }
+
+    trace_tpm_emulator_set_state_blob(type, tsb->size, flags);
+
+    return 0;
+}
+
+/*
+ * Set all the TPM state blobs.
+ *
+ * Returns a negative errno code in case of error.
+ */
+static int tpm_emulator_set_state_blobs(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+    trace_tpm_emulator_set_state_blobs();
+
+    if (tpm_emulator_stop_tpm(tb) < 0) {
+        trace_tpm_emulator_set_state_blobs_error("Could not stop TPM");
+        return -EIO;
+    }
+
+    if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
+                                    &state_blobs->permanent,
+                                    state_blobs->permanent_flags) < 0 ||
+        tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
+                                    &state_blobs->volatil,
+                                    state_blobs->volatil_flags) < 0 ||
+        tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
+                                    &state_blobs->savestate,
+                                    state_blobs->savestate_flags) < 0) {
+        return -EIO;
+    }
+
+    trace_tpm_emulator_set_state_blobs_done();
+
+    return 0;
+}
+
+static int tpm_emulator_pre_save(void *opaque)
+{
+    TPMBackend *tb = opaque;
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+    trace_tpm_emulator_pre_save();
+
+    tpm_backend_finish_sync(tb);
+
+    /* get the state blobs from the TPM */
+    return tpm_emulator_get_state_blobs(tpm_emu);
+}
+
+/*
+ * Load the TPM state blobs into the TPM.
+ *
+ * Returns negative errno codes in case of error.
+ */
+static int tpm_emulator_post_load(void *opaque, int version_id)
+{
+    TPMBackend *tb = opaque;
+    int ret;
+
+    ret = tpm_emulator_set_state_blobs(tb);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (tpm_emulator_startup_tpm_resume(tb, 0, true) < 0) {
+        return -EIO;
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_tpm_emulator = {
+    .name = "tpm-emulator",
+    .version_id = 0,
+    .pre_save = tpm_emulator_pre_save,
+    .post_load = tpm_emulator_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator),
+        VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator),
+        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.permanent.buffer,
+                                     TPMEmulator, 0, 0,
+                                     state_blobs.permanent.size),
+
+        VMSTATE_UINT32(state_blobs.volatil_flags, TPMEmulator),
+        VMSTATE_UINT32(state_blobs.volatil.size, TPMEmulator),
+        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.volatil.buffer,
+                                     TPMEmulator, 0, 0,
+                                     state_blobs.volatil.size),
+
+        VMSTATE_UINT32(state_blobs.savestate_flags, TPMEmulator),
+        VMSTATE_UINT32(state_blobs.savestate.size, TPMEmulator),
+        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.savestate.buffer,
+                                     TPMEmulator, 0, 0,
+                                     state_blobs.savestate.size),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tpm_emulator_inst_init(Object *obj)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
+
+    trace_tpm_emulator_inst_init();
+
+    tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
+    tpm_emu->cur_locty_number = ~0;
+    qemu_mutex_init(&tpm_emu->mutex);
+
+    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
+                     &vmstate_tpm_emulator, obj);
+}
+
+/*
+ * Gracefully shut down the external TPM
+ */
+static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
+{
+    ptm_res res;
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) {
+        error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
+                     strerror(errno));
+    } else if (res != 0) {
+        error_report("tpm-emulator: TPM result for shutdown: 0x%x %s",
+                     be32_to_cpu(res), tpm_emulator_strerror(be32_to_cpu(res)));
+    }
+}
+
+static void tpm_emulator_inst_finalize(Object *obj)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
+    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+    tpm_emulator_shutdown(tpm_emu);
+
+    object_unref(OBJECT(tpm_emu->data_ioc));
+
+    qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false);
+
+    qapi_free_TPMEmulatorOptions(tpm_emu->options);
+
+    if (tpm_emu->migration_blocker) {
+        migrate_del_blocker(tpm_emu->migration_blocker);
+        error_free(tpm_emu->migration_blocker);
+    }
+
+    tpm_sized_buffer_reset(&state_blobs->volatil);
+    tpm_sized_buffer_reset(&state_blobs->permanent);
+    tpm_sized_buffer_reset(&state_blobs->savestate);
+
+    qemu_mutex_destroy(&tpm_emu->mutex);
+
+    vmstate_unregister(NULL, &vmstate_tpm_emulator, obj);
+}
+
+static void tpm_emulator_class_init(ObjectClass *klass, void *data)
+{
+    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+
+    tbc->type = TPM_TYPE_EMULATOR;
+    tbc->opts = tpm_emulator_cmdline_opts;
+    tbc->desc = "TPM emulator backend driver";
+    tbc->create = tpm_emulator_create;
+    tbc->startup_tpm = tpm_emulator_startup_tpm;
+    tbc->cancel_cmd = tpm_emulator_cancel_cmd;
+    tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
+    tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
+    tbc->get_tpm_version = tpm_emulator_get_tpm_version;
+    tbc->get_buffer_size = tpm_emulator_get_buffer_size;
+    tbc->get_tpm_options = tpm_emulator_get_tpm_options;
+
+    tbc->handle_request = tpm_emulator_handle_request;
+}
+
+static const TypeInfo tpm_emulator_info = {
+    .name = TYPE_TPM_EMULATOR,
+    .parent = TYPE_TPM_BACKEND,
+    .instance_size = sizeof(TPMEmulator),
+    .class_init = tpm_emulator_class_init,
+    .instance_init = tpm_emulator_inst_init,
+    .instance_finalize = tpm_emulator_inst_finalize,
+};
+
+static void tpm_emulator_register(void)
+{
+    type_register_static(&tpm_emulator_info);
+}
+
+type_init(tpm_emulator_register)
diff --git a/backends/tpm/tpm_int.h b/backends/tpm/tpm_int.h
new file mode 100644 (file)
index 0000000..ba61093
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * TPM configuration
+ *
+ * Copyright (C) 2011-2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef BACKENDS_TPM_INT_H
+#define BACKENDS_TPM_INT_H
+
+#include "qemu/option.h"
+#include "sysemu/tpm.h"
+
+#define TPM_STANDARD_CMDLINE_OPTS \
+    { \
+        .name = "type", \
+        .type = QEMU_OPT_STRING, \
+        .help = "Type of TPM backend", \
+    }
+
+struct tpm_req_hdr {
+    uint16_t tag;
+    uint32_t len;
+    uint32_t ordinal;
+} QEMU_PACKED;
+
+struct tpm_resp_hdr {
+    uint16_t tag;
+    uint32_t len;
+    uint32_t errcode;
+} QEMU_PACKED;
+
+#define TPM_TAG_RQU_COMMAND       0xc1
+#define TPM_TAG_RQU_AUTH1_COMMAND 0xc2
+#define TPM_TAG_RQU_AUTH2_COMMAND 0xc3
+
+#define TPM_TAG_RSP_COMMAND       0xc4
+#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5
+#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6
+
+#define TPM_BAD_PARAMETER         3
+#define TPM_FAIL                  9
+#define TPM_KEYNOTFOUND           13
+#define TPM_BAD_PARAM_SIZE        25
+#define TPM_ENCRYPT_ERROR         32
+#define TPM_DECRYPT_ERROR         33
+#define TPM_BAD_KEY_PROPERTY      40
+#define TPM_BAD_MODE              44
+#define TPM_BAD_VERSION           46
+#define TPM_BAD_LOCALITY          61
+
+#define TPM_ORD_ContinueSelfTest  0x53
+#define TPM_ORD_GetTicks          0xf1
+#define TPM_ORD_GetCapability     0x65
+
+#define TPM_CAP_PROPERTY          0x05
+
+#define TPM_CAP_PROP_INPUT_BUFFER 0x124
+
+/* TPM2 defines */
+#define TPM2_ST_NO_SESSIONS       0x8001
+
+#define TPM2_CC_ReadClock         0x00000181
+#define TPM2_CC_GetCapability     0x0000017a
+
+#define TPM2_CAP_TPM_PROPERTIES   0x6
+
+#define TPM2_PT_MAX_COMMAND_SIZE  0x11e
+
+#define TPM_RC_INSUFFICIENT       0x9a
+#define TPM_RC_FAILURE            0x101
+#define TPM_RC_LOCALITY           0x907
+
+int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
+                             size_t *buffersize);
+
+typedef struct TPMSizedBuffer {
+    uint32_t size;
+    uint8_t  *buffer;
+} TPMSizedBuffer;
+
+void tpm_sized_buffer_reset(TPMSizedBuffer *tsb);
+
+#endif /* BACKENDS_TPM_INT_H */
diff --git a/backends/tpm/tpm_ioctl.h b/backends/tpm/tpm_ioctl.h
new file mode 100644 (file)
index 0000000..f5f5c55
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * tpm_ioctl.h
+ *
+ * (c) Copyright IBM Corporation 2014, 2015.
+ *
+ * This file is licensed under the terms of the 3-clause BSD license
+ */
+
+#ifndef TPM_IOCTL_H
+#define TPM_IOCTL_H
+
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+
+/*
+ * Every response from a command involving a TPM command execution must hold
+ * the ptm_res as the first element.
+ * ptm_res corresponds to the error code of a command executed by the TPM.
+ */
+
+typedef uint32_t ptm_res;
+
+/* PTM_GET_TPMESTABLISHED: get the establishment bit */
+struct ptm_est {
+    union {
+        struct {
+            ptm_res tpm_result;
+            unsigned char bit; /* TPM established bit */
+        } resp; /* response */
+    } u;
+};
+
+/* PTM_RESET_TPMESTABLISHED: reset establishment bit */
+struct ptm_reset_est {
+    union {
+        struct {
+            uint8_t loc; /* locality to use */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/* PTM_INIT */
+struct ptm_init {
+    union {
+        struct {
+            uint32_t init_flags; /* see definitions below */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/* above init_flags */
+#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)
+    /* delete volatile state file after reading it */
+
+/* PTM_SET_LOCALITY */
+struct ptm_loc {
+    union {
+        struct {
+            uint8_t loc; /* locality to set */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/* PTM_HASH_DATA: hash given data */
+struct ptm_hdata {
+    union {
+        struct {
+            uint32_t length;
+            uint8_t data[4096];
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/*
+ * size of the TPM state blob to transfer; x86_64 can handle 8k,
+ * ppc64le only ~7k; keep the response below a 4k page size
+ */
+#define PTM_STATE_BLOB_SIZE (3 * 1024)
+
+/*
+ * The following is the data structure to get state blobs from the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads
+ * with this ioctl and with adjusted offset are necessary. All bytes
+ * must be transferred and the transfer is done once the last byte has been
+ * returned.
+ * It is possible to use the read() interface for reading the data; however, the
+ * first bytes of the state blob will be part of the response to the ioctl(); a
+ * subsequent read() is only necessary if the total length (totlength) exceeds
+ * the number of received bytes. seek() is not supported.
+ */
+struct ptm_getstate {
+    union {
+        struct {
+            uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */
+            uint32_t type;        /* which blob to pull */
+            uint32_t offset;      /* offset from where to read */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+            uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */
+            uint32_t totlength;   /* total length that will be transferred */
+            uint32_t length;      /* number of bytes in following buffer */
+            uint8_t  data[PTM_STATE_BLOB_SIZE];
+        } resp; /* response */
+    } u;
+};
+
+/* TPM state blob types */
+#define PTM_BLOB_TYPE_PERMANENT  1
+#define PTM_BLOB_TYPE_VOLATILE   2
+#define PTM_BLOB_TYPE_SAVESTATE  3
+
+/* state_flags above : */
+#define PTM_STATE_FLAG_DECRYPTED     1 /* on input:  get decrypted state */
+#define PTM_STATE_FLAG_ENCRYPTED     2 /* on output: state is encrypted */
+
+/*
+ * The following is the data structure to set state blobs in the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple
+ * 'writes' using this ioctl are necessary. The last packet is indicated
+ * by the length being smaller than the PTM_STATE_BLOB_SIZE.
+ * The very first packet may have a length indicator of '0' enabling
+ * a write() with all the bytes from a buffer. If the write() interface
+ * is used, a final ioctl with a non-full buffer must be made to indicate
+ * that all data were transferred (a write with 0 bytes would not work).
+ */
+struct ptm_setstate {
+    union {
+        struct {
+            uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */
+            uint32_t type;        /* which blob to set */
+            uint32_t length;      /* length of the data;
+                                     use 0 on the first packet to
+                                     transfer using write() */
+            uint8_t data[PTM_STATE_BLOB_SIZE];
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/*
+ * PTM_GET_CONFIG: Data structure to get runtime configuration information
+ * such as which keys are applied.
+ */
+struct ptm_getconfig {
+    union {
+        struct {
+            ptm_res tpm_result;
+            uint32_t flags;
+        } resp; /* response */
+    } u;
+};
+
+#define PTM_CONFIG_FLAG_FILE_KEY        0x1
+#define PTM_CONFIG_FLAG_MIGRATION_KEY   0x2
+
+/*
+ * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the TPM.
+ * A 0 on input queries for the current buffer size. Any other
+ * number will try to set the buffer size. The returned number is
+ * the buffer size that will be used, which can be larger than the
+ * requested one, if it was below the minimum, or smaller than the
+ * requested one, if it was above the maximum.
+ */
+struct ptm_setbuffersize {
+    union {
+        struct {
+            uint32_t buffersize; /* 0 to query for current buffer size */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+            uint32_t buffersize; /* buffer size in use */
+            uint32_t minsize; /* min. supported buffer size */
+            uint32_t maxsize; /* max. supported buffer size */
+        } resp; /* response */
+    } u;
+};
+
+
+typedef uint64_t ptm_cap;
+typedef struct ptm_est ptm_est;
+typedef struct ptm_reset_est ptm_reset_est;
+typedef struct ptm_loc ptm_loc;
+typedef struct ptm_hdata ptm_hdata;
+typedef struct ptm_init ptm_init;
+typedef struct ptm_getstate ptm_getstate;
+typedef struct ptm_setstate ptm_setstate;
+typedef struct ptm_getconfig ptm_getconfig;
+typedef struct ptm_setbuffersize ptm_setbuffersize;
+
+/* capability flags returned by PTM_GET_CAPABILITY */
+#define PTM_CAP_INIT               (1)
+#define PTM_CAP_SHUTDOWN           (1 << 1)
+#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)
+#define PTM_CAP_SET_LOCALITY       (1 << 3)
+#define PTM_CAP_HASHING            (1 << 4)
+#define PTM_CAP_CANCEL_TPM_CMD     (1 << 5)
+#define PTM_CAP_STORE_VOLATILE     (1 << 6)
+#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)
+#define PTM_CAP_GET_STATEBLOB      (1 << 8)
+#define PTM_CAP_SET_STATEBLOB      (1 << 9)
+#define PTM_CAP_STOP               (1 << 10)
+#define PTM_CAP_GET_CONFIG         (1 << 11)
+#define PTM_CAP_SET_DATAFD         (1 << 12)
+#define PTM_CAP_SET_BUFFERSIZE     (1 << 13)
+
+enum {
+    PTM_GET_CAPABILITY     = _IOR('P', 0, ptm_cap),
+    PTM_INIT               = _IOWR('P', 1, ptm_init),
+    PTM_SHUTDOWN           = _IOR('P', 2, ptm_res),
+    PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),
+    PTM_SET_LOCALITY       = _IOWR('P', 4, ptm_loc),
+    PTM_HASH_START         = _IOR('P', 5, ptm_res),
+    PTM_HASH_DATA          = _IOWR('P', 6, ptm_hdata),
+    PTM_HASH_END           = _IOR('P', 7, ptm_res),
+    PTM_CANCEL_TPM_CMD     = _IOR('P', 8, ptm_res),
+    PTM_STORE_VOLATILE     = _IOR('P', 9, ptm_res),
+    PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),
+    PTM_GET_STATEBLOB      = _IOWR('P', 11, ptm_getstate),
+    PTM_SET_STATEBLOB      = _IOWR('P', 12, ptm_setstate),
+    PTM_STOP               = _IOR('P', 13, ptm_res),
+    PTM_GET_CONFIG         = _IOR('P', 14, ptm_getconfig),
+    PTM_SET_DATAFD         = _IOR('P', 15, ptm_res),
+    PTM_SET_BUFFERSIZE     = _IOWR('P', 16, ptm_setbuffersize),
+};
+
+/*
+ * Commands used by the non-CUSE TPMs
+ *
+ * All messages container big-endian data.
+ *
+ * The return messages only contain the 'resp' part of the unions
+ * in the data structures above. Besides that the limits in the
+ * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data
+ * and ptm_set_state:u.req.data) are 0xffffffff.
+ */
+enum {
+    CMD_GET_CAPABILITY = 1,
+    CMD_INIT,
+    CMD_SHUTDOWN,
+    CMD_GET_TPMESTABLISHED,
+    CMD_SET_LOCALITY,
+    CMD_HASH_START,
+    CMD_HASH_DATA,
+    CMD_HASH_END,
+    CMD_CANCEL_TPM_CMD,
+    CMD_STORE_VOLATILE,
+    CMD_RESET_TPMESTABLISHED,
+    CMD_GET_STATEBLOB,
+    CMD_SET_STATEBLOB,
+    CMD_STOP,
+    CMD_GET_CONFIG,
+    CMD_SET_DATAFD,
+    CMD_SET_BUFFERSIZE,
+};
+
+#endif /* TPM_IOCTL_H */
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
new file mode 100644 (file)
index 0000000..7403807
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ *  passthrough TPM driver
+ *
+ *  Copyright (c) 2010 - 2013 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ *  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/osdep.h"
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "qemu/sockets.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+#include "tpm_int.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+#include "trace.h"
+
+#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
+#define TPM_PASSTHROUGH(obj) \
+    OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
+
+/* data structures */
+struct TPMPassthruState {
+    TPMBackend parent;
+
+    TPMPassthroughOptions *options;
+    const char *tpm_dev;
+    int tpm_fd;
+    bool tpm_executing;
+    bool tpm_op_canceled;
+    int cancel_fd;
+
+    TPMVersion tpm_version;
+    size_t tpm_buffersize;
+};
+
+typedef struct TPMPassthruState TPMPassthruState;
+
+#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
+
+/* functions */
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
+
+static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
+{
+    int ret;
+ reread:
+    ret = read(fd, buf, len);
+    if (ret < 0) {
+        if (errno != EINTR && errno != EAGAIN) {
+            return -1;
+        }
+        goto reread;
+    }
+    return ret;
+}
+
+static void tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
+                                         const uint8_t *in, uint32_t in_len,
+                                         uint8_t *out, uint32_t out_len,
+                                         bool *selftest_done, Error **errp)
+{
+    ssize_t ret;
+    bool is_selftest;
+
+    /* FIXME: protect shared variables or use other sync mechanism */
+    tpm_pt->tpm_op_canceled = false;
+    tpm_pt->tpm_executing = true;
+    *selftest_done = false;
+
+    is_selftest = tpm_util_is_selftest(in, in_len);
+
+    ret = qemu_write_full(tpm_pt->tpm_fd, in, in_len);
+    if (ret != in_len) {
+        if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
+            error_setg_errno(errp, errno, "tpm_passthrough: error while "
+                             "transmitting data to TPM");
+        }
+        goto err_exit;
+    }
+
+    tpm_pt->tpm_executing = false;
+
+    ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
+    if (ret < 0) {
+        if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
+            error_setg_errno(errp, errno, "tpm_passthrough: error while "
+                             "reading data from TPM");
+        }
+    } else if (ret < sizeof(struct tpm_resp_hdr) ||
+               tpm_cmd_get_size(out) != ret) {
+        ret = -1;
+        error_setg_errno(errp, errno, "tpm_passthrough: received invalid "
+                     "response packet from TPM");
+    }
+
+    if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
+        *selftest_done = tpm_cmd_get_errcode(out) == 0;
+    }
+
+err_exit:
+    if (ret < 0) {
+        tpm_util_write_fatal_error_response(out, out_len);
+    }
+
+    tpm_pt->tpm_executing = false;
+}
+
+static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
+                                           Error **errp)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+    trace_tpm_passthrough_handle_request(cmd);
+
+    tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len,
+                                 cmd->out, cmd->out_len, &cmd->selftest_done,
+                                 errp);
+}
+
+static void tpm_passthrough_reset(TPMBackend *tb)
+{
+    trace_tpm_passthrough_reset();
+
+    tpm_passthrough_cancel_cmd(tb);
+}
+
+static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
+{
+    return false;
+}
+
+static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
+                                                      uint8_t locty)
+{
+    /* only a TPM 2.0 will support this */
+    return 0;
+}
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+    int n;
+
+    /*
+     * As of Linux 3.7 the tpm_tis driver does not properly cancel
+     * commands on all TPM manufacturers' TPMs.
+     * Only cancel if we're busy so we don't cancel someone else's
+     * command, e.g., a command executed on the host.
+     */
+    if (tpm_pt->tpm_executing) {
+        if (tpm_pt->cancel_fd >= 0) {
+            tpm_pt->tpm_op_canceled = true;
+            n = write(tpm_pt->cancel_fd, "-", 1);
+            if (n != 1) {
+                error_report("Canceling TPM command failed: %s",
+                             strerror(errno));
+            }
+        } else {
+            error_report("Cannot cancel TPM command due to missing "
+                         "TPM sysfs cancel entry");
+        }
+    }
+}
+
+static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+    return tpm_pt->tpm_version;
+}
+
+static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+    int ret;
+
+    ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version,
+                                   &tpm_pt->tpm_buffersize);
+    if (ret < 0) {
+        tpm_pt->tpm_buffersize = 4096;
+    }
+    return tpm_pt->tpm_buffersize;
+}
+
+/*
+ * Unless path or file descriptor set has been provided by user,
+ * determine the sysfs cancel file following kernel documentation
+ * in Documentation/ABI/stable/sysfs-class-tpm.
+ * From /dev/tpm0 create /sys/class/tpm/tpm0/device/cancel
+ * before 4.0: /sys/class/misc/tpm0/device/cancel
+ */
+static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
+{
+    int fd = -1;
+    char *dev;
+    char path[PATH_MAX];
+
+    if (tpm_pt->options->cancel_path) {
+        fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY);
+        if (fd < 0) {
+            error_report("tpm_passthrough: Could not open TPM cancel path: %s",
+                         strerror(errno));
+        }
+        return fd;
+    }
+
+    dev = strrchr(tpm_pt->tpm_dev, '/');
+    if (!dev) {
+        error_report("tpm_passthrough: Bad TPM device path %s",
+                     tpm_pt->tpm_dev);
+        return -1;
+    }
+
+    dev++;
+    if (snprintf(path, sizeof(path), "/sys/class/tpm/%s/device/cancel",
+                 dev) < sizeof(path)) {
+        fd = qemu_open(path, O_WRONLY);
+        if (fd < 0) {
+            if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel",
+                         dev) < sizeof(path)) {
+                fd = qemu_open(path, O_WRONLY);
+            }
+        }
+    }
+
+    if (fd < 0) {
+        error_report("tpm_passthrough: Could not guess TPM cancel path");
+    } else {
+        tpm_pt->options->cancel_path = g_strdup(path);
+    }
+
+    return fd;
+}
+
+static int
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+{
+    const char *value;
+
+    value = qemu_opt_get(opts, "cancel-path");
+    if (value) {
+        tpm_pt->options->cancel_path = g_strdup(value);
+        tpm_pt->options->has_cancel_path = true;
+    }
+
+    value = qemu_opt_get(opts, "path");
+    if (value) {
+        tpm_pt->options->has_path = true;
+        tpm_pt->options->path = g_strdup(value);
+    }
+
+    tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+    tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
+    if (tpm_pt->tpm_fd < 0) {
+        error_report("Cannot access TPM device using '%s': %s",
+                     tpm_pt->tpm_dev, strerror(errno));
+        return -1;
+    }
+
+    if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
+        error_report("'%s' is not a TPM device.",
+                     tpm_pt->tpm_dev);
+        return -1;
+    }
+
+    tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
+    if (tpm_pt->cancel_fd < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+{
+    Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
+
+    if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+        object_unref(obj);
+        return NULL;
+    }
+
+    return TPM_BACKEND(obj);
+}
+
+static int tpm_passthrough_startup_tpm(TPMBackend *tb, size_t buffersize)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+    if (buffersize && buffersize < tpm_pt->tpm_buffersize) {
+        error_report("Requested buffer size of %zu is smaller than host TPM's "
+                     "fixed buffer size of %zu",
+                     buffersize, tpm_pt->tpm_buffersize);
+        return -1;
+    }
+
+    return 0;
+}
+
+static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
+{
+    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
+
+    options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
+    options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
+                                             TPM_PASSTHROUGH(tb)->options);
+
+    return options;
+}
+
+static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {
+        .name = "cancel-path",
+        .type = QEMU_OPT_STRING,
+        .help = "Sysfs file entry for canceling TPM commands",
+    },
+    {
+        .name = "path",
+        .type = QEMU_OPT_STRING,
+        .help = "Path to TPM device on the host",
+    },
+    { /* end of list */ },
+};
+
+static void tpm_passthrough_inst_init(Object *obj)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
+
+    tpm_pt->options = g_new0(TPMPassthroughOptions, 1);
+    tpm_pt->tpm_fd = -1;
+    tpm_pt->cancel_fd = -1;
+}
+
+static void tpm_passthrough_inst_finalize(Object *obj)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
+
+    tpm_passthrough_cancel_cmd(TPM_BACKEND(obj));
+
+    if (tpm_pt->tpm_fd >= 0) {
+        qemu_close(tpm_pt->tpm_fd);
+    }
+    if (tpm_pt->cancel_fd >= 0) {
+        qemu_close(tpm_pt->cancel_fd);
+    }
+    qapi_free_TPMPassthroughOptions(tpm_pt->options);
+}
+
+static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
+{
+    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+
+    tbc->type = TPM_TYPE_PASSTHROUGH;
+    tbc->opts = tpm_passthrough_cmdline_opts;
+    tbc->desc = "Passthrough TPM backend driver";
+    tbc->create = tpm_passthrough_create;
+    tbc->startup_tpm = tpm_passthrough_startup_tpm;
+    tbc->reset = tpm_passthrough_reset;
+    tbc->cancel_cmd = tpm_passthrough_cancel_cmd;
+    tbc->get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag;
+    tbc->reset_tpm_established_flag =
+        tpm_passthrough_reset_tpm_established_flag;
+    tbc->get_tpm_version = tpm_passthrough_get_tpm_version;
+    tbc->get_buffer_size = tpm_passthrough_get_buffer_size;
+    tbc->get_tpm_options = tpm_passthrough_get_tpm_options;
+    tbc->handle_request = tpm_passthrough_handle_request;
+}
+
+static const TypeInfo tpm_passthrough_info = {
+    .name = TYPE_TPM_PASSTHROUGH,
+    .parent = TYPE_TPM_BACKEND,
+    .instance_size = sizeof(TPMPassthruState),
+    .class_init = tpm_passthrough_class_init,
+    .instance_init = tpm_passthrough_inst_init,
+    .instance_finalize = tpm_passthrough_inst_finalize,
+};
+
+static void tpm_passthrough_register(void)
+{
+    type_register_static(&tpm_passthrough_info);
+}
+
+type_init(tpm_passthrough_register)
diff --git a/backends/tpm/tpm_util.c b/backends/tpm/tpm_util.c
new file mode 100644 (file)
index 0000000..cfc7572
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * TPM utility functions
+ *
+ *  Copyright (c) 2010 - 2015 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ * 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/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "tpm_int.h"
+#include "exec/memory.h"
+#include "hw/qdev-properties.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+#include "trace.h"
+
+/* tpm backend property */
+
+static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
+                    Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    TPMBackend **be = qdev_get_prop_ptr(dev, opaque);
+    char *p;
+
+    p = g_strdup(*be ? (*be)->id : "");
+    visit_type_str(v, name, &p, errp);
+    g_free(p);
+}
+
+static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
+                    Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Error *local_err = NULL;
+    Property *prop = opaque;
+    TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
+    char *str;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_str(v, name, &str, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    s = qemu_find_tpm_be(str);
+    if (s == NULL) {
+        error_setg(errp, "Property '%s.%s' can't find value '%s'",
+                   object_get_typename(obj), prop->name, str);
+    } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) {
+        *be = s; /* weak reference, avoid cyclic ref */
+    }
+    g_free(str);
+}
+
+static void release_tpm(Object *obj, const char *name, void *opaque)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    TPMBackend **be = qdev_get_prop_ptr(dev, prop);
+
+    if (*be) {
+        tpm_backend_reset(*be);
+    }
+}
+
+const PropertyInfo qdev_prop_tpm = {
+    .name  = "str",
+    .description = "ID of a tpm to use as a backend",
+    .get   = get_tpm,
+    .set   = set_tpm,
+    .release = release_tpm,
+};
+
+/*
+ * Write an error message in the given output buffer.
+ */
+void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len)
+{
+    if (out_len >= sizeof(struct tpm_resp_hdr)) {
+        tpm_cmd_set_tag(out, TPM_TAG_RSP_COMMAND);
+        tpm_cmd_set_size(out, sizeof(struct tpm_resp_hdr));
+        tpm_cmd_set_error(out, TPM_FAIL);
+    }
+}
+
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
+{
+    if (in_len >= sizeof(struct tpm_req_hdr)) {
+        return tpm_cmd_get_ordinal(in) == TPM_ORD_ContinueSelfTest;
+    }
+
+    return false;
+}
+
+/*
+ * Send request to a TPM device. We expect a response within one second.
+ */
+static int tpm_util_request(int fd,
+                            const void *request,
+                            size_t requestlen,
+                            void *response,
+                            size_t responselen)
+{
+    fd_set readfds;
+    int n;
+    struct timeval tv = {
+        .tv_sec = 1,
+        .tv_usec = 0,
+    };
+
+    n = write(fd, request, requestlen);
+    if (n < 0) {
+        return -errno;
+    }
+    if (n != requestlen) {
+        return -EFAULT;
+    }
+
+    FD_ZERO(&readfds);
+    FD_SET(fd, &readfds);
+
+    /* wait for a second */
+    n = select(fd + 1, &readfds, NULL, NULL, &tv);
+    if (n != 1) {
+        return -errno;
+    }
+
+    n = read(fd, response, responselen);
+    if (n < sizeof(struct tpm_resp_hdr)) {
+        return -EFAULT;
+    }
+
+    /* check the header */
+    if (tpm_cmd_get_size(response) != n) {
+        return -EMSGSIZE;
+    }
+
+    return 0;
+}
+
+/*
+ * A basic test of a TPM device. We expect a well formatted response header
+ * (error response is fine).
+ */
+static int tpm_util_test(int fd,
+                         const void *request,
+                         size_t requestlen,
+                         uint16_t *return_tag)
+{
+    char buf[1024];
+    ssize_t ret;
+
+    ret = tpm_util_request(fd, request, requestlen,
+                           buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    *return_tag = tpm_cmd_get_tag(buf);
+
+    return 0;
+}
+
+/*
+ * Probe for the TPM device in the back
+ * Returns 0 on success with the version of the probed TPM set, 1 on failure.
+ */
+int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
+{
+    /*
+     * Sending a TPM1.2 command to a TPM2 should return a TPM1.2
+     * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e)
+     *
+     * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the
+     * header.
+     * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag
+     * in the header and an error code.
+     */
+    const struct tpm_req_hdr test_req = {
+        .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
+        .len = cpu_to_be32(sizeof(test_req)),
+        .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
+    };
+
+    const struct tpm_req_hdr test_req_tpm2 = {
+        .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+        .len = cpu_to_be32(sizeof(test_req_tpm2)),
+        .ordinal = cpu_to_be32(TPM2_CC_ReadClock),
+    };
+    uint16_t return_tag;
+    int ret;
+
+    /* Send TPM 2 command */
+    ret = tpm_util_test(tpm_fd, &test_req_tpm2,
+                        sizeof(test_req_tpm2), &return_tag);
+    /* TPM 2 would respond with a tag of TPM2_ST_NO_SESSIONS */
+    if (!ret && return_tag == TPM2_ST_NO_SESSIONS) {
+        *tpm_version = TPM_VERSION_2_0;
+        return 0;
+    }
+
+    /* Send TPM 1.2 command */
+    ret = tpm_util_test(tpm_fd, &test_req,
+                        sizeof(test_req), &return_tag);
+    if (!ret && return_tag == TPM_TAG_RSP_COMMAND) {
+        *tpm_version = TPM_VERSION_1_2;
+        /* this is a TPM 1.2 */
+        return 0;
+    }
+
+    *tpm_version = TPM_VERSION_UNSPEC;
+
+    return 1;
+}
+
+int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
+                             size_t *buffersize)
+{
+    int ret;
+
+    switch (tpm_version) {
+    case TPM_VERSION_1_2: {
+        const struct tpm_req_get_buffer_size {
+            struct tpm_req_hdr hdr;
+            uint32_t capability;
+            uint32_t len;
+            uint32_t subcap;
+        } QEMU_PACKED tpm_get_buffer_size = {
+            .hdr = {
+                .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
+                .len = cpu_to_be32(sizeof(tpm_get_buffer_size)),
+                .ordinal = cpu_to_be32(TPM_ORD_GetCapability),
+            },
+            .capability = cpu_to_be32(TPM_CAP_PROPERTY),
+            .len = cpu_to_be32(sizeof(uint32_t)),
+            .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER),
+        };
+        struct tpm_resp_get_buffer_size {
+            struct tpm_resp_hdr hdr;
+            uint32_t len;
+            uint32_t buffersize;
+        } QEMU_PACKED tpm_resp;
+
+        ret = tpm_util_request(tpm_fd, &tpm_get_buffer_size,
+                               sizeof(tpm_get_buffer_size),
+                               &tpm_resp, sizeof(tpm_resp));
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (be32_to_cpu(tpm_resp.hdr.len) != sizeof(tpm_resp) ||
+            be32_to_cpu(tpm_resp.len) != sizeof(uint32_t)) {
+            trace_tpm_util_get_buffer_size_hdr_len(
+                be32_to_cpu(tpm_resp.hdr.len),
+                sizeof(tpm_resp));
+            trace_tpm_util_get_buffer_size_len(be32_to_cpu(tpm_resp.len),
+                                               sizeof(uint32_t));
+            error_report("tpm_util: Got unexpected response to "
+                         "TPM_GetCapability; errcode: 0x%x",
+                         be32_to_cpu(tpm_resp.hdr.errcode));
+            return -EFAULT;
+        }
+        *buffersize = be32_to_cpu(tpm_resp.buffersize);
+        break;
+    }
+    case TPM_VERSION_2_0: {
+        const struct tpm2_req_get_buffer_size {
+            struct tpm_req_hdr hdr;
+            uint32_t capability;
+            uint32_t property;
+            uint32_t count;
+        } QEMU_PACKED tpm2_get_buffer_size = {
+            .hdr = {
+                .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+                .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)),
+                .ordinal = cpu_to_be32(TPM2_CC_GetCapability),
+            },
+            .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES),
+            .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE),
+            .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */
+        };
+        struct tpm2_resp_get_buffer_size {
+            struct tpm_resp_hdr hdr;
+            uint8_t more;
+            uint32_t capability;
+            uint32_t count;
+            uint32_t property1;
+            uint32_t value1;
+            uint32_t property2;
+            uint32_t value2;
+        } QEMU_PACKED tpm2_resp;
+
+        ret = tpm_util_request(tpm_fd, &tpm2_get_buffer_size,
+                               sizeof(tpm2_get_buffer_size),
+                               &tpm2_resp, sizeof(tpm2_resp));
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (be32_to_cpu(tpm2_resp.hdr.len) != sizeof(tpm2_resp) ||
+            be32_to_cpu(tpm2_resp.count) != 2) {
+            trace_tpm_util_get_buffer_size_hdr_len2(
+                be32_to_cpu(tpm2_resp.hdr.len),
+                sizeof(tpm2_resp));
+            trace_tpm_util_get_buffer_size_len2(
+                be32_to_cpu(tpm2_resp.count), 2);
+            error_report("tpm_util: Got unexpected response to "
+                         "TPM2_GetCapability; errcode: 0x%x",
+                         be32_to_cpu(tpm2_resp.hdr.errcode));
+            return -EFAULT;
+        }
+        *buffersize = MAX(be32_to_cpu(tpm2_resp.value1),
+                          be32_to_cpu(tpm2_resp.value2));
+        break;
+    }
+    case TPM_VERSION_UNSPEC:
+        return -EFAULT;
+    }
+
+    trace_tpm_util_get_buffer_size(*buffersize);
+
+    return 0;
+}
+
+void tpm_sized_buffer_reset(TPMSizedBuffer *tsb)
+{
+    g_free(tsb->buffer);
+    tsb->buffer = NULL;
+    tsb->size = 0;
+}
+
+void tpm_util_show_buffer(const unsigned char *buffer,
+                          size_t buffer_size, const char *string)
+{
+    size_t len, i;
+    char *line_buffer, *p;
+
+    if (!trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) {
+        return;
+    }
+    len = MIN(tpm_cmd_get_size(buffer), buffer_size);
+
+    /*
+     * allocate enough room for 3 chars per buffer entry plus a
+     * newline after every 16 chars and a final null terminator.
+     */
+    line_buffer = g_malloc(len * 3 + (len / 16) + 1);
+
+    for (i = 0, p = line_buffer; i < len; i++) {
+        if (i && !(i % 16)) {
+            p += sprintf(p, "\n");
+        }
+        p += sprintf(p, "%.2X ", buffer[i]);
+    }
+    trace_tpm_util_show_buffer(string, len, line_buffer);
+
+    g_free(line_buffer);
+}
diff --git a/backends/tpm/trace-events b/backends/tpm/trace-events
new file mode 100644 (file)
index 0000000..0a2591f
--- /dev/null
@@ -0,0 +1,33 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# tpm_passthrough.c
+tpm_passthrough_handle_request(void *cmd) "processing command %p"
+tpm_passthrough_reset(void) "reset"
+
+# tpm_util.c
+tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
+tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"
+tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu"
+tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu"
+tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu"
+tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s"
+
+# tpm_emulator.c
+tpm_emulator_set_locality(uint8_t locty) "setting locality to %d"
+tpm_emulator_handle_request(void) "processing TPM command"
+tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64
+tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u"
+tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu"
+tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d"
+tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD"
+tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2"
+tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2"
+tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified"
+tpm_emulator_handle_device_opts_startup_error(void) "Startup error"
+tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x"
+tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x"
+tpm_emulator_set_state_blobs(void) "setting state blobs"
+tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s"
+tpm_emulator_set_state_blobs_done(void) "Done setting state blobs"
+tpm_emulator_pre_save(void) ""
+tpm_emulator_inst_init(void) ""
index 0200fdac68573397c50d4e36c12b91c21e78c534..ed6c0d785df1cc04b2825c6a477d72f878bdc872 100644 (file)
@@ -232,8 +232,8 @@ Integrity Measurement Architecture (IMA), are not expecting to share
 PCRs.
 
 QEMU files related to the TPM passthrough device:
- - ``hw/tpm/tpm_passthrough.c``
- - ``hw/tpm/tpm_util.c``
+ - ``backends/tpm/tpm_passthrough.c``
+ - ``backends/tpm/tpm_util.c``
  - ``include/sysemu/tpm_util.h``
 
 
@@ -292,8 +292,8 @@ instrumented to initialize a TPM 1.2 or TPM 2 device using this
 command.
 
 QEMU files related to the TPM emulator device:
- - ``hw/tpm/tpm_emulator.c``
- - ``hw/tpm/tpm_util.c``
+ - ``backends/tpm/tpm_emulator.c``
+ - ``backends/tpm/tpm_util.c``
  - ``include/sysemu/tpm_util.h``
 
 The following commands start the swtpm with a UnixIO control channel over
index 5028fd8880a147756867c1416ddbccaa75d8d5d8..29e82f3c92d9534076834b1e8822c06eec83057d 100644 (file)
@@ -1,7 +1,3 @@
-config TPM_BACKEND
-    bool
-    depends on TPM
-
 config TPM_TIS_ISA
     bool
     depends on TPM && ISA_BUS
@@ -22,17 +18,6 @@ config TPM_CRB
     depends on TPM && PC
     select TPM_BACKEND
 
-config TPM_PASSTHROUGH
-    bool
-    default y
-    # FIXME: should check for x86 host as well
-    depends on TPM_BACKEND && LINUX
-
-config TPM_EMULATOR
-    bool
-    default y
-    depends on TPM_BACKEND
-
 config TPM_SPAPR
     bool
     default y
index f1ec4beb95cfb4ec7149e66c172a2371beb5b198..6fc05be67c7bb41d01e7613e33fa5913abd65988 100644 (file)
@@ -1,9 +1,6 @@
-common-obj-$(CONFIG_TPM) += tpm_util.o
 obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o
 common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o
 common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o
 common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o
 common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
-common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
-common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
 obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o
diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
deleted file mode 100644 (file)
index 9605339..0000000
+++ /dev/null
@@ -1,997 +0,0 @@
-/*
- *  Emulator TPM driver
- *
- *  Copyright (c) 2017 Intel Corporation
- *  Author: Amarnath Valluri <amarnath.valluri@intel.com>
- *
- *  Copyright (c) 2010 - 2013, 2018 IBM Corporation
- *  Authors:
- *    Stefan Berger <stefanb@us.ibm.com>
- *
- *  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/osdep.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qemu/sockets.h"
-#include "io/channel-socket.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/tpm_util.h"
-#include "tpm_int.h"
-#include "tpm_ioctl.h"
-#include "migration/blocker.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qapi/clone-visitor.h"
-#include "qapi/qapi-visit-tpm.h"
-#include "chardev/char-fe.h"
-#include "trace.h"
-
-#define TYPE_TPM_EMULATOR "tpm-emulator"
-#define TPM_EMULATOR(obj) \
-    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
-
-#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
-
-/* data structures */
-
-/* blobs from the TPM; part of VM state when migrating */
-typedef struct TPMBlobBuffers {
-    uint32_t permanent_flags;
-    TPMSizedBuffer permanent;
-
-    uint32_t volatil_flags;
-    TPMSizedBuffer volatil;
-
-    uint32_t savestate_flags;
-    TPMSizedBuffer savestate;
-} TPMBlobBuffers;
-
-typedef struct TPMEmulator {
-    TPMBackend parent;
-
-    TPMEmulatorOptions *options;
-    CharBackend ctrl_chr;
-    QIOChannel *data_ioc;
-    TPMVersion tpm_version;
-    ptm_cap caps; /* capabilities of the TPM */
-    uint8_t cur_locty_number; /* last set locality */
-    Error *migration_blocker;
-
-    QemuMutex mutex;
-
-    unsigned int established_flag:1;
-    unsigned int established_flag_cached:1;
-
-    TPMBlobBuffers state_blobs;
-} TPMEmulator;
-
-struct tpm_error {
-    uint32_t tpm_result;
-    const char *string;
-};
-
-static const struct tpm_error tpm_errors[] = {
-    /* TPM 1.2 error codes */
-    { TPM_BAD_PARAMETER   , "a parameter is bad" },
-    { TPM_FAIL            , "operation failed" },
-    { TPM_KEYNOTFOUND     , "key could not be found" },
-    { TPM_BAD_PARAM_SIZE  , "bad parameter size"},
-    { TPM_ENCRYPT_ERROR   , "encryption error" },
-    { TPM_DECRYPT_ERROR   , "decryption error" },
-    { TPM_BAD_KEY_PROPERTY, "bad key property" },
-    { TPM_BAD_MODE        , "bad (encryption) mode" },
-    { TPM_BAD_VERSION     , "bad version identifier" },
-    { TPM_BAD_LOCALITY    , "bad locality" },
-    /* TPM 2 error codes */
-    { TPM_RC_FAILURE     , "operation failed" },
-    { TPM_RC_LOCALITY    , "bad locality"     },
-    { TPM_RC_INSUFFICIENT, "insufficient amount of data" },
-};
-
-static const char *tpm_emulator_strerror(uint32_t tpm_result)
-{
-    size_t i;
-
-    for (i = 0; i < ARRAY_SIZE(tpm_errors); i++) {
-        if (tpm_errors[i].tpm_result == tpm_result) {
-            return tpm_errors[i].string;
-        }
-    }
-    return "";
-}
-
-static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
-                                size_t msg_len_in, size_t msg_len_out)
-{
-    CharBackend *dev = &tpm->ctrl_chr;
-    uint32_t cmd_no = cpu_to_be32(cmd);
-    ssize_t n = sizeof(uint32_t) + msg_len_in;
-    uint8_t *buf = NULL;
-    int ret = -1;
-
-    qemu_mutex_lock(&tpm->mutex);
-
-    buf = g_alloca(n);
-    memcpy(buf, &cmd_no, sizeof(cmd_no));
-    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
-
-    n = qemu_chr_fe_write_all(dev, buf, n);
-    if (n <= 0) {
-        goto end;
-    }
-
-    if (msg_len_out != 0) {
-        n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
-        if (n <= 0) {
-            goto end;
-        }
-    }
-
-    ret = 0;
-
-end:
-    qemu_mutex_unlock(&tpm->mutex);
-    return ret;
-}
-
-static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
-                                     const uint8_t *in, uint32_t in_len,
-                                     uint8_t *out, uint32_t out_len,
-                                     bool *selftest_done,
-                                     Error **errp)
-{
-    ssize_t ret;
-    bool is_selftest = false;
-
-    if (selftest_done) {
-        *selftest_done = false;
-        is_selftest = tpm_util_is_selftest(in, in_len);
-    }
-
-    ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp);
-    if (ret != 0) {
-        return -1;
-    }
-
-    ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out,
-              sizeof(struct tpm_resp_hdr), errp);
-    if (ret != 0) {
-        return -1;
-    }
-
-    ret = qio_channel_read_all(tpm_emu->data_ioc,
-              (char *)out + sizeof(struct tpm_resp_hdr),
-              tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp);
-    if (ret != 0) {
-        return -1;
-    }
-
-    if (is_selftest) {
-        *selftest_done = tpm_cmd_get_errcode(out) == 0;
-    }
-
-    return 0;
-}
-
-static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
-                                     Error **errp)
-{
-    ptm_loc loc;
-
-    if (tpm_emu->cur_locty_number == locty_number) {
-        return 0;
-    }
-
-    trace_tpm_emulator_set_locality(locty_number);
-
-    memset(&loc, 0, sizeof(loc));
-    loc.u.req.loc = locty_number;
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc,
-                             sizeof(loc), sizeof(loc)) < 0) {
-        error_setg(errp, "tpm-emulator: could not set locality : %s",
-                   strerror(errno));
-        return -1;
-    }
-
-    loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
-    if (loc.u.resp.tpm_result != 0) {
-        error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x",
-                   loc.u.resp.tpm_result);
-        return -1;
-    }
-
-    tpm_emu->cur_locty_number = locty_number;
-
-    return 0;
-}
-
-static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
-                                        Error **errp)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-
-    trace_tpm_emulator_handle_request();
-
-    if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 ||
-        tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len,
-                                  cmd->out, cmd->out_len,
-                                  &cmd->selftest_done, errp) < 0) {
-        tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
-    }
-}
-
-static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
-{
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY,
-                             &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
-        error_report("tpm-emulator: probing failed : %s", strerror(errno));
-        return -1;
-    }
-
-    tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
-
-    trace_tpm_emulator_probe_caps(tpm_emu->caps);
-
-    return 0;
-}
-
-static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
-{
-    ptm_cap caps = 0;
-    const char *tpm = NULL;
-
-    /* check for min. required capabilities */
-    switch (tpm_emu->tpm_version) {
-    case TPM_VERSION_1_2:
-        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
-               PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP |
-               PTM_CAP_SET_BUFFERSIZE;
-        tpm = "1.2";
-        break;
-    case TPM_VERSION_2_0:
-        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
-               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
-               PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
-        tpm = "2";
-        break;
-    case TPM_VERSION_UNSPEC:
-        error_report("tpm-emulator: TPM version has not been set");
-        return -1;
-    }
-
-    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
-        error_report("tpm-emulator: TPM does not implement minimum set of "
-                     "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int tpm_emulator_stop_tpm(TPMBackend *tb)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    ptm_res res;
-
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
-        error_report("tpm-emulator: Could not stop TPM: %s",
-                     strerror(errno));
-        return -1;
-    }
-
-    res = be32_to_cpu(res);
-    if (res) {
-        error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x %s", res,
-                     tpm_emulator_strerror(res));
-        return -1;
-    }
-
-    return 0;
-}
-
-static int tpm_emulator_set_buffer_size(TPMBackend *tb,
-                                        size_t wanted_size,
-                                        size_t *actual_size)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    ptm_setbuffersize psbs;
-
-    if (tpm_emulator_stop_tpm(tb) < 0) {
-        return -1;
-    }
-
-    psbs.u.req.buffersize = cpu_to_be32(wanted_size);
-
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
-                             sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
-        error_report("tpm-emulator: Could not set buffer size: %s",
-                     strerror(errno));
-        return -1;
-    }
-
-    psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result);
-    if (psbs.u.resp.tpm_result != 0) {
-        error_report("tpm-emulator: TPM result for set buffer size : 0x%x %s",
-                     psbs.u.resp.tpm_result,
-                     tpm_emulator_strerror(psbs.u.resp.tpm_result));
-        return -1;
-    }
-
-    if (actual_size) {
-        *actual_size = be32_to_cpu(psbs.u.resp.buffersize);
-    }
-
-    trace_tpm_emulator_set_buffer_size(
-            be32_to_cpu(psbs.u.resp.buffersize),
-            be32_to_cpu(psbs.u.resp.minsize),
-            be32_to_cpu(psbs.u.resp.maxsize));
-
-    return 0;
-}
-
-static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize,
-                                     bool is_resume)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    ptm_init init = {
-        .u.req.init_flags = 0,
-    };
-    ptm_res res;
-
-    trace_tpm_emulator_startup_tpm_resume(is_resume, buffersize);
-
-    if (buffersize != 0 &&
-        tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
-        goto err_exit;
-    }
-
-    if (is_resume) {
-        init.u.req.init_flags |= cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE);
-    }
-
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
-                             sizeof(init)) < 0) {
-        error_report("tpm-emulator: could not send INIT: %s",
-                     strerror(errno));
-        goto err_exit;
-    }
-
-    res = be32_to_cpu(init.u.resp.tpm_result);
-    if (res) {
-        error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x %s", res,
-                     tpm_emulator_strerror(res));
-        goto err_exit;
-    }
-    return 0;
-
-err_exit:
-    return -1;
-}
-
-static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
-{
-    return tpm_emulator_startup_tpm_resume(tb, buffersize, false);
-}
-
-static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    ptm_est est;
-
-    if (tpm_emu->established_flag_cached) {
-        return tpm_emu->established_flag;
-    }
-
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est,
-                             0, sizeof(est)) < 0) {
-        error_report("tpm-emulator: Could not get the TPM established flag: %s",
-                     strerror(errno));
-        return false;
-    }
-    trace_tpm_emulator_get_tpm_established_flag(est.u.resp.bit);
-
-    tpm_emu->established_flag_cached = 1;
-    tpm_emu->established_flag = (est.u.resp.bit != 0);
-
-    return tpm_emu->established_flag;
-}
-
-static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
-                                                   uint8_t locty)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    ptm_reset_est reset_est;
-    ptm_res res;
-
-    /* only a TPM 2.0 will support this */
-    if (tpm_emu->tpm_version != TPM_VERSION_2_0) {
-        return 0;
-    }
-
-    reset_est.u.req.loc = tpm_emu->cur_locty_number;
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED,
-                             &reset_est, sizeof(reset_est),
-                             sizeof(reset_est)) < 0) {
-        error_report("tpm-emulator: Could not reset the establishment bit: %s",
-                     strerror(errno));
-        return -1;
-    }
-
-    res = be32_to_cpu(reset_est.u.resp.tpm_result);
-    if (res) {
-        error_report(
-            "tpm-emulator: TPM result for rest established flag: 0x%x %s",
-            res, tpm_emulator_strerror(res));
-        return -1;
-    }
-
-    tpm_emu->established_flag_cached = 0;
-
-    return 0;
-}
-
-static void tpm_emulator_cancel_cmd(TPMBackend *tb)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    ptm_res res;
-
-    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) {
-        trace_tpm_emulator_cancel_cmd_not_supt();
-        return;
-    }
-
-    /* FIXME: make the function non-blocking, or it may block a VCPU */
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
-                             sizeof(res)) < 0) {
-        error_report("tpm-emulator: Could not cancel command: %s",
-                     strerror(errno));
-    } else if (res != 0) {
-        error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
-                     be32_to_cpu(res));
-    }
-}
-
-static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-
-    return tpm_emu->tpm_version;
-}
-
-static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
-{
-    size_t actual_size;
-
-    if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) {
-        return 4096;
-    }
-
-    return actual_size;
-}
-
-static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
-{
-    Error *err = NULL;
-    ptm_cap caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB |
-                   PTM_CAP_STOP;
-
-    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
-        error_setg(&tpm_emu->migration_blocker,
-                   "Migration disabled: TPM emulator does not support "
-                   "migration");
-        migrate_add_blocker(tpm_emu->migration_blocker, &err);
-        if (err) {
-            error_report_err(err);
-            error_free(tpm_emu->migration_blocker);
-            tpm_emu->migration_blocker = NULL;
-
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
-{
-    ptm_res res;
-    Error *err = NULL;
-    int fds[2] = { -1, -1 };
-
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
-        error_report("tpm-emulator: Failed to create socketpair");
-        return -1;
-    }
-
-    qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
-
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0,
-                             sizeof(res)) < 0 || res != 0) {
-        error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
-                     strerror(errno));
-        goto err_exit;
-    }
-
-    tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));
-    if (err) {
-        error_prepend(&err, "tpm-emulator: Failed to create io channel: ");
-        error_report_err(err);
-        goto err_exit;
-    }
-
-    closesocket(fds[1]);
-
-    return 0;
-
-err_exit:
-    closesocket(fds[0]);
-    closesocket(fds[1]);
-    return -1;
-}
-
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
-{
-    const char *value;
-
-    value = qemu_opt_get(opts, "chardev");
-    if (value) {
-        Error *err = NULL;
-        Chardev *dev = qemu_chr_find(value);
-
-        if (!dev) {
-            error_report("tpm-emulator: tpm chardev '%s' not found.", value);
-            goto err;
-        }
-
-        if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
-            error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
-                          value);
-            error_report_err(err);
-            goto err;
-        }
-
-        tpm_emu->options->chardev = g_strdup(value);
-    }
-
-    if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
-        goto err;
-    }
-
-    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
-     * by passthrough driver, which not yet using GIOChannel.
-     */
-    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
-                             &tpm_emu->tpm_version)) {
-        error_report("'%s' is not emulating TPM device. Error: %s",
-                      tpm_emu->options->chardev, strerror(errno));
-        goto err;
-    }
-
-    switch (tpm_emu->tpm_version) {
-    case TPM_VERSION_1_2:
-        trace_tpm_emulator_handle_device_opts_tpm12();
-        break;
-    case TPM_VERSION_2_0:
-        trace_tpm_emulator_handle_device_opts_tpm2();
-        break;
-    default:
-        trace_tpm_emulator_handle_device_opts_unspec();
-    }
-
-    if (tpm_emulator_probe_caps(tpm_emu) ||
-        tpm_emulator_check_caps(tpm_emu)) {
-        goto err;
-    }
-
-    return tpm_emulator_block_migration(tpm_emu);
-
-err:
-    trace_tpm_emulator_handle_device_opts_startup_error();
-
-    return -1;
-}
-
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
-{
-    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
-
-    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
-        object_unref(OBJECT(tb));
-        return NULL;
-    }
-
-    return tb;
-}
-
-static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
-
-    options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
-    options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
-
-    return options;
-}
-
-static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
-    TPM_STANDARD_CMDLINE_OPTS,
-    {
-        .name = "chardev",
-        .type = QEMU_OPT_STRING,
-        .help = "Character device to use for out-of-band control messages",
-    },
-    { /* end of list */ },
-};
-
-/*
- * Transfer a TPM state blob from the TPM into a provided buffer.
- *
- * @tpm_emu: TPMEmulator
- * @type: the type of blob to transfer
- * @tsb: the TPMSizeBuffer to fill with the blob
- * @flags: the flags to return to the caller
- */
-static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu,
-                                       uint8_t type,
-                                       TPMSizedBuffer *tsb,
-                                       uint32_t *flags)
-{
-    ptm_getstate pgs;
-    ptm_res res;
-    ssize_t n;
-    uint32_t totlength, length;
-
-    tpm_sized_buffer_reset(tsb);
-
-    pgs.u.req.state_flags = cpu_to_be32(PTM_STATE_FLAG_DECRYPTED);
-    pgs.u.req.type = cpu_to_be32(type);
-    pgs.u.req.offset = 0;
-
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB,
-                             &pgs, sizeof(pgs.u.req),
-                             offsetof(ptm_getstate, u.resp.data)) < 0) {
-        error_report("tpm-emulator: could not get state blob type %d : %s",
-                     type, strerror(errno));
-        return -1;
-    }
-
-    res = be32_to_cpu(pgs.u.resp.tpm_result);
-    if (res != 0 && (res & 0x800) == 0) {
-        error_report("tpm-emulator: Getting the stateblob (type %d) failed "
-                     "with a TPM error 0x%x %s", type, res,
-                     tpm_emulator_strerror(res));
-        return -1;
-    }
-
-    totlength = be32_to_cpu(pgs.u.resp.totlength);
-    length = be32_to_cpu(pgs.u.resp.length);
-    if (totlength != length) {
-        error_report("tpm-emulator: Expecting to read %u bytes "
-                     "but would get %u", totlength, length);
-        return -1;
-    }
-
-    *flags = be32_to_cpu(pgs.u.resp.state_flags);
-
-    if (totlength > 0) {
-        tsb->buffer = g_try_malloc(totlength);
-        if (!tsb->buffer) {
-            error_report("tpm-emulator: Out of memory allocating %u bytes",
-                         totlength);
-            return -1;
-        }
-
-        n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, tsb->buffer, totlength);
-        if (n != totlength) {
-            error_report("tpm-emulator: Could not read stateblob (type %d); "
-                         "expected %u bytes, got %zd",
-                         type, totlength, n);
-            return -1;
-        }
-    }
-    tsb->size = totlength;
-
-    trace_tpm_emulator_get_state_blob(type, tsb->size, *flags);
-
-    return 0;
-}
-
-static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu)
-{
-    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
-
-    if (tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
-                                    &state_blobs->permanent,
-                                    &state_blobs->permanent_flags) < 0 ||
-        tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
-                                    &state_blobs->volatil,
-                                    &state_blobs->volatil_flags) < 0 ||
-        tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
-                                    &state_blobs->savestate,
-                                    &state_blobs->savestate_flags) < 0) {
-        goto err_exit;
-    }
-
-    return 0;
-
- err_exit:
-    tpm_sized_buffer_reset(&state_blobs->volatil);
-    tpm_sized_buffer_reset(&state_blobs->permanent);
-    tpm_sized_buffer_reset(&state_blobs->savestate);
-
-    return -1;
-}
-
-/*
- * Transfer a TPM state blob to the TPM emulator.
- *
- * @tpm_emu: TPMEmulator
- * @type: the type of TPM state blob to transfer
- * @tsb: TPMSizedBuffer containing the TPM state blob
- * @flags: Flags describing the (encryption) state of the TPM state blob
- */
-static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
-                                       uint32_t type,
-                                       TPMSizedBuffer *tsb,
-                                       uint32_t flags)
-{
-    ssize_t n;
-    ptm_setstate pss;
-    ptm_res tpm_result;
-
-    if (tsb->size == 0) {
-        return 0;
-    }
-
-    pss = (ptm_setstate) {
-        .u.req.state_flags = cpu_to_be32(flags),
-        .u.req.type = cpu_to_be32(type),
-        .u.req.length = cpu_to_be32(tsb->size),
-    };
-
-    /* write the header only */
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss,
-                             offsetof(ptm_setstate, u.req.data), 0) < 0) {
-        error_report("tpm-emulator: could not set state blob type %d : %s",
-                     type, strerror(errno));
-        return -1;
-    }
-
-    /* now the body */
-    n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size);
-    if (n != tsb->size) {
-        error_report("tpm-emulator: Writing the stateblob (type %d) "
-                     "failed; could not write %u bytes, but only %zd",
-                     type, tsb->size, n);
-        return -1;
-    }
-
-    /* now get the result */
-    n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr,
-                             (uint8_t *)&pss, sizeof(pss.u.resp));
-    if (n != sizeof(pss.u.resp)) {
-        error_report("tpm-emulator: Reading response from writing stateblob "
-                     "(type %d) failed; expected %zu bytes, got %zd", type,
-                     sizeof(pss.u.resp), n);
-        return -1;
-    }
-
-    tpm_result = be32_to_cpu(pss.u.resp.tpm_result);
-    if (tpm_result != 0) {
-        error_report("tpm-emulator: Setting the stateblob (type %d) failed "
-                     "with a TPM error 0x%x %s", type, tpm_result,
-                     tpm_emulator_strerror(tpm_result));
-        return -1;
-    }
-
-    trace_tpm_emulator_set_state_blob(type, tsb->size, flags);
-
-    return 0;
-}
-
-/*
- * Set all the TPM state blobs.
- *
- * Returns a negative errno code in case of error.
- */
-static int tpm_emulator_set_state_blobs(TPMBackend *tb)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
-
-    trace_tpm_emulator_set_state_blobs();
-
-    if (tpm_emulator_stop_tpm(tb) < 0) {
-        trace_tpm_emulator_set_state_blobs_error("Could not stop TPM");
-        return -EIO;
-    }
-
-    if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
-                                    &state_blobs->permanent,
-                                    state_blobs->permanent_flags) < 0 ||
-        tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
-                                    &state_blobs->volatil,
-                                    state_blobs->volatil_flags) < 0 ||
-        tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
-                                    &state_blobs->savestate,
-                                    state_blobs->savestate_flags) < 0) {
-        return -EIO;
-    }
-
-    trace_tpm_emulator_set_state_blobs_done();
-
-    return 0;
-}
-
-static int tpm_emulator_pre_save(void *opaque)
-{
-    TPMBackend *tb = opaque;
-    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-
-    trace_tpm_emulator_pre_save();
-
-    tpm_backend_finish_sync(tb);
-
-    /* get the state blobs from the TPM */
-    return tpm_emulator_get_state_blobs(tpm_emu);
-}
-
-/*
- * Load the TPM state blobs into the TPM.
- *
- * Returns negative errno codes in case of error.
- */
-static int tpm_emulator_post_load(void *opaque, int version_id)
-{
-    TPMBackend *tb = opaque;
-    int ret;
-
-    ret = tpm_emulator_set_state_blobs(tb);
-    if (ret < 0) {
-        return ret;
-    }
-
-    if (tpm_emulator_startup_tpm_resume(tb, 0, true) < 0) {
-        return -EIO;
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_tpm_emulator = {
-    .name = "tpm-emulator",
-    .version_id = 0,
-    .pre_save = tpm_emulator_pre_save,
-    .post_load = tpm_emulator_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator),
-        VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator),
-        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.permanent.buffer,
-                                     TPMEmulator, 0, 0,
-                                     state_blobs.permanent.size),
-
-        VMSTATE_UINT32(state_blobs.volatil_flags, TPMEmulator),
-        VMSTATE_UINT32(state_blobs.volatil.size, TPMEmulator),
-        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.volatil.buffer,
-                                     TPMEmulator, 0, 0,
-                                     state_blobs.volatil.size),
-
-        VMSTATE_UINT32(state_blobs.savestate_flags, TPMEmulator),
-        VMSTATE_UINT32(state_blobs.savestate.size, TPMEmulator),
-        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.savestate.buffer,
-                                     TPMEmulator, 0, 0,
-                                     state_blobs.savestate.size),
-
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void tpm_emulator_inst_init(Object *obj)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
-
-    trace_tpm_emulator_inst_init();
-
-    tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
-    tpm_emu->cur_locty_number = ~0;
-    qemu_mutex_init(&tpm_emu->mutex);
-
-    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
-                     &vmstate_tpm_emulator, obj);
-}
-
-/*
- * Gracefully shut down the external TPM
- */
-static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
-{
-    ptm_res res;
-
-    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) {
-        error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
-                     strerror(errno));
-    } else if (res != 0) {
-        error_report("tpm-emulator: TPM result for shutdown: 0x%x %s",
-                     be32_to_cpu(res), tpm_emulator_strerror(be32_to_cpu(res)));
-    }
-}
-
-static void tpm_emulator_inst_finalize(Object *obj)
-{
-    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
-    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
-
-    tpm_emulator_shutdown(tpm_emu);
-
-    object_unref(OBJECT(tpm_emu->data_ioc));
-
-    qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false);
-
-    qapi_free_TPMEmulatorOptions(tpm_emu->options);
-
-    if (tpm_emu->migration_blocker) {
-        migrate_del_blocker(tpm_emu->migration_blocker);
-        error_free(tpm_emu->migration_blocker);
-    }
-
-    tpm_sized_buffer_reset(&state_blobs->volatil);
-    tpm_sized_buffer_reset(&state_blobs->permanent);
-    tpm_sized_buffer_reset(&state_blobs->savestate);
-
-    qemu_mutex_destroy(&tpm_emu->mutex);
-
-    vmstate_unregister(NULL, &vmstate_tpm_emulator, obj);
-}
-
-static void tpm_emulator_class_init(ObjectClass *klass, void *data)
-{
-    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
-
-    tbc->type = TPM_TYPE_EMULATOR;
-    tbc->opts = tpm_emulator_cmdline_opts;
-    tbc->desc = "TPM emulator backend driver";
-    tbc->create = tpm_emulator_create;
-    tbc->startup_tpm = tpm_emulator_startup_tpm;
-    tbc->cancel_cmd = tpm_emulator_cancel_cmd;
-    tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
-    tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
-    tbc->get_tpm_version = tpm_emulator_get_tpm_version;
-    tbc->get_buffer_size = tpm_emulator_get_buffer_size;
-    tbc->get_tpm_options = tpm_emulator_get_tpm_options;
-
-    tbc->handle_request = tpm_emulator_handle_request;
-}
-
-static const TypeInfo tpm_emulator_info = {
-    .name = TYPE_TPM_EMULATOR,
-    .parent = TYPE_TPM_BACKEND,
-    .instance_size = sizeof(TPMEmulator),
-    .class_init = tpm_emulator_class_init,
-    .instance_init = tpm_emulator_inst_init,
-    .instance_finalize = tpm_emulator_inst_finalize,
-};
-
-static void tpm_emulator_register(void)
-{
-    type_register_static(&tpm_emulator_info);
-}
-
-type_init(tpm_emulator_register)
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
deleted file mode 100644 (file)
index 9f72879..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * TPM configuration
- *
- * Copyright (C) 2011-2013 IBM Corporation
- *
- * Authors:
- *  Stefan Berger    <stefanb@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#ifndef TPM_TPM_INT_H
-#define TPM_TPM_INT_H
-
-#include "qemu/option.h"
-#include "sysemu/tpm.h"
-
-#define TPM_STANDARD_CMDLINE_OPTS \
-    { \
-        .name = "type", \
-        .type = QEMU_OPT_STRING, \
-        .help = "Type of TPM backend", \
-    }
-
-struct tpm_req_hdr {
-    uint16_t tag;
-    uint32_t len;
-    uint32_t ordinal;
-} QEMU_PACKED;
-
-struct tpm_resp_hdr {
-    uint16_t tag;
-    uint32_t len;
-    uint32_t errcode;
-} QEMU_PACKED;
-
-#define TPM_TAG_RQU_COMMAND       0xc1
-#define TPM_TAG_RQU_AUTH1_COMMAND 0xc2
-#define TPM_TAG_RQU_AUTH2_COMMAND 0xc3
-
-#define TPM_TAG_RSP_COMMAND       0xc4
-#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5
-#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6
-
-#define TPM_BAD_PARAMETER         3
-#define TPM_FAIL                  9
-#define TPM_KEYNOTFOUND           13
-#define TPM_BAD_PARAM_SIZE        25
-#define TPM_ENCRYPT_ERROR         32
-#define TPM_DECRYPT_ERROR         33
-#define TPM_BAD_KEY_PROPERTY      40
-#define TPM_BAD_MODE              44
-#define TPM_BAD_VERSION           46
-#define TPM_BAD_LOCALITY          61
-
-#define TPM_ORD_ContinueSelfTest  0x53
-#define TPM_ORD_GetTicks          0xf1
-#define TPM_ORD_GetCapability     0x65
-
-#define TPM_CAP_PROPERTY          0x05
-
-#define TPM_CAP_PROP_INPUT_BUFFER 0x124
-
-/* TPM2 defines */
-#define TPM2_ST_NO_SESSIONS       0x8001
-
-#define TPM2_CC_ReadClock         0x00000181
-#define TPM2_CC_GetCapability     0x0000017a
-
-#define TPM2_CAP_TPM_PROPERTIES   0x6
-
-#define TPM2_PT_MAX_COMMAND_SIZE  0x11e
-
-#define TPM_RC_INSUFFICIENT       0x9a
-#define TPM_RC_FAILURE            0x101
-#define TPM_RC_LOCALITY           0x907
-
-int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
-                             size_t *buffersize);
-
-typedef struct TPMSizedBuffer {
-    uint32_t size;
-    uint8_t  *buffer;
-} TPMSizedBuffer;
-
-void tpm_sized_buffer_reset(TPMSizedBuffer *tsb);
-
-#endif /* TPM_TPM_INT_H */
diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
deleted file mode 100644 (file)
index f5f5c55..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * tpm_ioctl.h
- *
- * (c) Copyright IBM Corporation 2014, 2015.
- *
- * This file is licensed under the terms of the 3-clause BSD license
- */
-
-#ifndef TPM_IOCTL_H
-#define TPM_IOCTL_H
-
-#include <sys/uio.h>
-#include <sys/ioctl.h>
-
-/*
- * Every response from a command involving a TPM command execution must hold
- * the ptm_res as the first element.
- * ptm_res corresponds to the error code of a command executed by the TPM.
- */
-
-typedef uint32_t ptm_res;
-
-/* PTM_GET_TPMESTABLISHED: get the establishment bit */
-struct ptm_est {
-    union {
-        struct {
-            ptm_res tpm_result;
-            unsigned char bit; /* TPM established bit */
-        } resp; /* response */
-    } u;
-};
-
-/* PTM_RESET_TPMESTABLISHED: reset establishment bit */
-struct ptm_reset_est {
-    union {
-        struct {
-            uint8_t loc; /* locality to use */
-        } req; /* request */
-        struct {
-            ptm_res tpm_result;
-        } resp; /* response */
-    } u;
-};
-
-/* PTM_INIT */
-struct ptm_init {
-    union {
-        struct {
-            uint32_t init_flags; /* see definitions below */
-        } req; /* request */
-        struct {
-            ptm_res tpm_result;
-        } resp; /* response */
-    } u;
-};
-
-/* above init_flags */
-#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)
-    /* delete volatile state file after reading it */
-
-/* PTM_SET_LOCALITY */
-struct ptm_loc {
-    union {
-        struct {
-            uint8_t loc; /* locality to set */
-        } req; /* request */
-        struct {
-            ptm_res tpm_result;
-        } resp; /* response */
-    } u;
-};
-
-/* PTM_HASH_DATA: hash given data */
-struct ptm_hdata {
-    union {
-        struct {
-            uint32_t length;
-            uint8_t data[4096];
-        } req; /* request */
-        struct {
-            ptm_res tpm_result;
-        } resp; /* response */
-    } u;
-};
-
-/*
- * size of the TPM state blob to transfer; x86_64 can handle 8k,
- * ppc64le only ~7k; keep the response below a 4k page size
- */
-#define PTM_STATE_BLOB_SIZE (3 * 1024)
-
-/*
- * The following is the data structure to get state blobs from the TPM.
- * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads
- * with this ioctl and with adjusted offset are necessary. All bytes
- * must be transferred and the transfer is done once the last byte has been
- * returned.
- * It is possible to use the read() interface for reading the data; however, the
- * first bytes of the state blob will be part of the response to the ioctl(); a
- * subsequent read() is only necessary if the total length (totlength) exceeds
- * the number of received bytes. seek() is not supported.
- */
-struct ptm_getstate {
-    union {
-        struct {
-            uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */
-            uint32_t type;        /* which blob to pull */
-            uint32_t offset;      /* offset from where to read */
-        } req; /* request */
-        struct {
-            ptm_res tpm_result;
-            uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */
-            uint32_t totlength;   /* total length that will be transferred */
-            uint32_t length;      /* number of bytes in following buffer */
-            uint8_t  data[PTM_STATE_BLOB_SIZE];
-        } resp; /* response */
-    } u;
-};
-
-/* TPM state blob types */
-#define PTM_BLOB_TYPE_PERMANENT  1
-#define PTM_BLOB_TYPE_VOLATILE   2
-#define PTM_BLOB_TYPE_SAVESTATE  3
-
-/* state_flags above : */
-#define PTM_STATE_FLAG_DECRYPTED     1 /* on input:  get decrypted state */
-#define PTM_STATE_FLAG_ENCRYPTED     2 /* on output: state is encrypted */
-
-/*
- * The following is the data structure to set state blobs in the TPM.
- * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple
- * 'writes' using this ioctl are necessary. The last packet is indicated
- * by the length being smaller than the PTM_STATE_BLOB_SIZE.
- * The very first packet may have a length indicator of '0' enabling
- * a write() with all the bytes from a buffer. If the write() interface
- * is used, a final ioctl with a non-full buffer must be made to indicate
- * that all data were transferred (a write with 0 bytes would not work).
- */
-struct ptm_setstate {
-    union {
-        struct {
-            uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */
-            uint32_t type;        /* which blob to set */
-            uint32_t length;      /* length of the data;
-                                     use 0 on the first packet to
-                                     transfer using write() */
-            uint8_t data[PTM_STATE_BLOB_SIZE];
-        } req; /* request */
-        struct {
-            ptm_res tpm_result;
-        } resp; /* response */
-    } u;
-};
-
-/*
- * PTM_GET_CONFIG: Data structure to get runtime configuration information
- * such as which keys are applied.
- */
-struct ptm_getconfig {
-    union {
-        struct {
-            ptm_res tpm_result;
-            uint32_t flags;
-        } resp; /* response */
-    } u;
-};
-
-#define PTM_CONFIG_FLAG_FILE_KEY        0x1
-#define PTM_CONFIG_FLAG_MIGRATION_KEY   0x2
-
-/*
- * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the TPM.
- * A 0 on input queries for the current buffer size. Any other
- * number will try to set the buffer size. The returned number is
- * the buffer size that will be used, which can be larger than the
- * requested one, if it was below the minimum, or smaller than the
- * requested one, if it was above the maximum.
- */
-struct ptm_setbuffersize {
-    union {
-        struct {
-            uint32_t buffersize; /* 0 to query for current buffer size */
-        } req; /* request */
-        struct {
-            ptm_res tpm_result;
-            uint32_t buffersize; /* buffer size in use */
-            uint32_t minsize; /* min. supported buffer size */
-            uint32_t maxsize; /* max. supported buffer size */
-        } resp; /* response */
-    } u;
-};
-
-
-typedef uint64_t ptm_cap;
-typedef struct ptm_est ptm_est;
-typedef struct ptm_reset_est ptm_reset_est;
-typedef struct ptm_loc ptm_loc;
-typedef struct ptm_hdata ptm_hdata;
-typedef struct ptm_init ptm_init;
-typedef struct ptm_getstate ptm_getstate;
-typedef struct ptm_setstate ptm_setstate;
-typedef struct ptm_getconfig ptm_getconfig;
-typedef struct ptm_setbuffersize ptm_setbuffersize;
-
-/* capability flags returned by PTM_GET_CAPABILITY */
-#define PTM_CAP_INIT               (1)
-#define PTM_CAP_SHUTDOWN           (1 << 1)
-#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)
-#define PTM_CAP_SET_LOCALITY       (1 << 3)
-#define PTM_CAP_HASHING            (1 << 4)
-#define PTM_CAP_CANCEL_TPM_CMD     (1 << 5)
-#define PTM_CAP_STORE_VOLATILE     (1 << 6)
-#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)
-#define PTM_CAP_GET_STATEBLOB      (1 << 8)
-#define PTM_CAP_SET_STATEBLOB      (1 << 9)
-#define PTM_CAP_STOP               (1 << 10)
-#define PTM_CAP_GET_CONFIG         (1 << 11)
-#define PTM_CAP_SET_DATAFD         (1 << 12)
-#define PTM_CAP_SET_BUFFERSIZE     (1 << 13)
-
-enum {
-    PTM_GET_CAPABILITY     = _IOR('P', 0, ptm_cap),
-    PTM_INIT               = _IOWR('P', 1, ptm_init),
-    PTM_SHUTDOWN           = _IOR('P', 2, ptm_res),
-    PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),
-    PTM_SET_LOCALITY       = _IOWR('P', 4, ptm_loc),
-    PTM_HASH_START         = _IOR('P', 5, ptm_res),
-    PTM_HASH_DATA          = _IOWR('P', 6, ptm_hdata),
-    PTM_HASH_END           = _IOR('P', 7, ptm_res),
-    PTM_CANCEL_TPM_CMD     = _IOR('P', 8, ptm_res),
-    PTM_STORE_VOLATILE     = _IOR('P', 9, ptm_res),
-    PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),
-    PTM_GET_STATEBLOB      = _IOWR('P', 11, ptm_getstate),
-    PTM_SET_STATEBLOB      = _IOWR('P', 12, ptm_setstate),
-    PTM_STOP               = _IOR('P', 13, ptm_res),
-    PTM_GET_CONFIG         = _IOR('P', 14, ptm_getconfig),
-    PTM_SET_DATAFD         = _IOR('P', 15, ptm_res),
-    PTM_SET_BUFFERSIZE     = _IOWR('P', 16, ptm_setbuffersize),
-};
-
-/*
- * Commands used by the non-CUSE TPMs
- *
- * All messages container big-endian data.
- *
- * The return messages only contain the 'resp' part of the unions
- * in the data structures above. Besides that the limits in the
- * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data
- * and ptm_set_state:u.req.data) are 0xffffffff.
- */
-enum {
-    CMD_GET_CAPABILITY = 1,
-    CMD_INIT,
-    CMD_SHUTDOWN,
-    CMD_GET_TPMESTABLISHED,
-    CMD_SET_LOCALITY,
-    CMD_HASH_START,
-    CMD_HASH_DATA,
-    CMD_HASH_END,
-    CMD_CANCEL_TPM_CMD,
-    CMD_STORE_VOLATILE,
-    CMD_RESET_TPMESTABLISHED,
-    CMD_GET_STATEBLOB,
-    CMD_SET_STATEBLOB,
-    CMD_STOP,
-    CMD_GET_CONFIG,
-    CMD_SET_DATAFD,
-    CMD_SET_BUFFERSIZE,
-};
-
-#endif /* TPM_IOCTL_H */
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
deleted file mode 100644 (file)
index 7403807..0000000
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- *  passthrough TPM driver
- *
- *  Copyright (c) 2010 - 2013 IBM Corporation
- *  Authors:
- *    Stefan Berger <stefanb@us.ibm.com>
- *
- *  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/osdep.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qemu/sockets.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/tpm_util.h"
-#include "tpm_int.h"
-#include "qapi/clone-visitor.h"
-#include "qapi/qapi-visit-tpm.h"
-#include "trace.h"
-
-#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
-#define TPM_PASSTHROUGH(obj) \
-    OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
-
-/* data structures */
-struct TPMPassthruState {
-    TPMBackend parent;
-
-    TPMPassthroughOptions *options;
-    const char *tpm_dev;
-    int tpm_fd;
-    bool tpm_executing;
-    bool tpm_op_canceled;
-    int cancel_fd;
-
-    TPMVersion tpm_version;
-    size_t tpm_buffersize;
-};
-
-typedef struct TPMPassthruState TPMPassthruState;
-
-#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
-
-/* functions */
-
-static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
-
-static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
-{
-    int ret;
- reread:
-    ret = read(fd, buf, len);
-    if (ret < 0) {
-        if (errno != EINTR && errno != EAGAIN) {
-            return -1;
-        }
-        goto reread;
-    }
-    return ret;
-}
-
-static void tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
-                                         const uint8_t *in, uint32_t in_len,
-                                         uint8_t *out, uint32_t out_len,
-                                         bool *selftest_done, Error **errp)
-{
-    ssize_t ret;
-    bool is_selftest;
-
-    /* FIXME: protect shared variables or use other sync mechanism */
-    tpm_pt->tpm_op_canceled = false;
-    tpm_pt->tpm_executing = true;
-    *selftest_done = false;
-
-    is_selftest = tpm_util_is_selftest(in, in_len);
-
-    ret = qemu_write_full(tpm_pt->tpm_fd, in, in_len);
-    if (ret != in_len) {
-        if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
-            error_setg_errno(errp, errno, "tpm_passthrough: error while "
-                             "transmitting data to TPM");
-        }
-        goto err_exit;
-    }
-
-    tpm_pt->tpm_executing = false;
-
-    ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
-    if (ret < 0) {
-        if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
-            error_setg_errno(errp, errno, "tpm_passthrough: error while "
-                             "reading data from TPM");
-        }
-    } else if (ret < sizeof(struct tpm_resp_hdr) ||
-               tpm_cmd_get_size(out) != ret) {
-        ret = -1;
-        error_setg_errno(errp, errno, "tpm_passthrough: received invalid "
-                     "response packet from TPM");
-    }
-
-    if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
-        *selftest_done = tpm_cmd_get_errcode(out) == 0;
-    }
-
-err_exit:
-    if (ret < 0) {
-        tpm_util_write_fatal_error_response(out, out_len);
-    }
-
-    tpm_pt->tpm_executing = false;
-}
-
-static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
-                                           Error **errp)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
-    trace_tpm_passthrough_handle_request(cmd);
-
-    tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len,
-                                 cmd->out, cmd->out_len, &cmd->selftest_done,
-                                 errp);
-}
-
-static void tpm_passthrough_reset(TPMBackend *tb)
-{
-    trace_tpm_passthrough_reset();
-
-    tpm_passthrough_cancel_cmd(tb);
-}
-
-static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
-{
-    return false;
-}
-
-static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
-                                                      uint8_t locty)
-{
-    /* only a TPM 2.0 will support this */
-    return 0;
-}
-
-static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-    int n;
-
-    /*
-     * As of Linux 3.7 the tpm_tis driver does not properly cancel
-     * commands on all TPM manufacturers' TPMs.
-     * Only cancel if we're busy so we don't cancel someone else's
-     * command, e.g., a command executed on the host.
-     */
-    if (tpm_pt->tpm_executing) {
-        if (tpm_pt->cancel_fd >= 0) {
-            tpm_pt->tpm_op_canceled = true;
-            n = write(tpm_pt->cancel_fd, "-", 1);
-            if (n != 1) {
-                error_report("Canceling TPM command failed: %s",
-                             strerror(errno));
-            }
-        } else {
-            error_report("Cannot cancel TPM command due to missing "
-                         "TPM sysfs cancel entry");
-        }
-    }
-}
-
-static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
-    return tpm_pt->tpm_version;
-}
-
-static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-    int ret;
-
-    ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version,
-                                   &tpm_pt->tpm_buffersize);
-    if (ret < 0) {
-        tpm_pt->tpm_buffersize = 4096;
-    }
-    return tpm_pt->tpm_buffersize;
-}
-
-/*
- * Unless path or file descriptor set has been provided by user,
- * determine the sysfs cancel file following kernel documentation
- * in Documentation/ABI/stable/sysfs-class-tpm.
- * From /dev/tpm0 create /sys/class/tpm/tpm0/device/cancel
- * before 4.0: /sys/class/misc/tpm0/device/cancel
- */
-static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
-{
-    int fd = -1;
-    char *dev;
-    char path[PATH_MAX];
-
-    if (tpm_pt->options->cancel_path) {
-        fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY);
-        if (fd < 0) {
-            error_report("tpm_passthrough: Could not open TPM cancel path: %s",
-                         strerror(errno));
-        }
-        return fd;
-    }
-
-    dev = strrchr(tpm_pt->tpm_dev, '/');
-    if (!dev) {
-        error_report("tpm_passthrough: Bad TPM device path %s",
-                     tpm_pt->tpm_dev);
-        return -1;
-    }
-
-    dev++;
-    if (snprintf(path, sizeof(path), "/sys/class/tpm/%s/device/cancel",
-                 dev) < sizeof(path)) {
-        fd = qemu_open(path, O_WRONLY);
-        if (fd < 0) {
-            if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel",
-                         dev) < sizeof(path)) {
-                fd = qemu_open(path, O_WRONLY);
-            }
-        }
-    }
-
-    if (fd < 0) {
-        error_report("tpm_passthrough: Could not guess TPM cancel path");
-    } else {
-        tpm_pt->options->cancel_path = g_strdup(path);
-    }
-
-    return fd;
-}
-
-static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
-{
-    const char *value;
-
-    value = qemu_opt_get(opts, "cancel-path");
-    if (value) {
-        tpm_pt->options->cancel_path = g_strdup(value);
-        tpm_pt->options->has_cancel_path = true;
-    }
-
-    value = qemu_opt_get(opts, "path");
-    if (value) {
-        tpm_pt->options->has_path = true;
-        tpm_pt->options->path = g_strdup(value);
-    }
-
-    tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
-    tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
-    if (tpm_pt->tpm_fd < 0) {
-        error_report("Cannot access TPM device using '%s': %s",
-                     tpm_pt->tpm_dev, strerror(errno));
-        return -1;
-    }
-
-    if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
-        error_report("'%s' is not a TPM device.",
-                     tpm_pt->tpm_dev);
-        return -1;
-    }
-
-    tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
-    if (tpm_pt->cancel_fd < 0) {
-        return -1;
-    }
-
-    return 0;
-}
-
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
-{
-    Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
-
-    if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
-        object_unref(obj);
-        return NULL;
-    }
-
-    return TPM_BACKEND(obj);
-}
-
-static int tpm_passthrough_startup_tpm(TPMBackend *tb, size_t buffersize)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
-    if (buffersize && buffersize < tpm_pt->tpm_buffersize) {
-        error_report("Requested buffer size of %zu is smaller than host TPM's "
-                     "fixed buffer size of %zu",
-                     buffersize, tpm_pt->tpm_buffersize);
-        return -1;
-    }
-
-    return 0;
-}
-
-static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
-{
-    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
-
-    options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
-    options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
-                                             TPM_PASSTHROUGH(tb)->options);
-
-    return options;
-}
-
-static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
-    TPM_STANDARD_CMDLINE_OPTS,
-    {
-        .name = "cancel-path",
-        .type = QEMU_OPT_STRING,
-        .help = "Sysfs file entry for canceling TPM commands",
-    },
-    {
-        .name = "path",
-        .type = QEMU_OPT_STRING,
-        .help = "Path to TPM device on the host",
-    },
-    { /* end of list */ },
-};
-
-static void tpm_passthrough_inst_init(Object *obj)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
-
-    tpm_pt->options = g_new0(TPMPassthroughOptions, 1);
-    tpm_pt->tpm_fd = -1;
-    tpm_pt->cancel_fd = -1;
-}
-
-static void tpm_passthrough_inst_finalize(Object *obj)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
-
-    tpm_passthrough_cancel_cmd(TPM_BACKEND(obj));
-
-    if (tpm_pt->tpm_fd >= 0) {
-        qemu_close(tpm_pt->tpm_fd);
-    }
-    if (tpm_pt->cancel_fd >= 0) {
-        qemu_close(tpm_pt->cancel_fd);
-    }
-    qapi_free_TPMPassthroughOptions(tpm_pt->options);
-}
-
-static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
-{
-    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
-
-    tbc->type = TPM_TYPE_PASSTHROUGH;
-    tbc->opts = tpm_passthrough_cmdline_opts;
-    tbc->desc = "Passthrough TPM backend driver";
-    tbc->create = tpm_passthrough_create;
-    tbc->startup_tpm = tpm_passthrough_startup_tpm;
-    tbc->reset = tpm_passthrough_reset;
-    tbc->cancel_cmd = tpm_passthrough_cancel_cmd;
-    tbc->get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag;
-    tbc->reset_tpm_established_flag =
-        tpm_passthrough_reset_tpm_established_flag;
-    tbc->get_tpm_version = tpm_passthrough_get_tpm_version;
-    tbc->get_buffer_size = tpm_passthrough_get_buffer_size;
-    tbc->get_tpm_options = tpm_passthrough_get_tpm_options;
-    tbc->handle_request = tpm_passthrough_handle_request;
-}
-
-static const TypeInfo tpm_passthrough_info = {
-    .name = TYPE_TPM_PASSTHROUGH,
-    .parent = TYPE_TPM_BACKEND,
-    .instance_size = sizeof(TPMPassthruState),
-    .class_init = tpm_passthrough_class_init,
-    .instance_init = tpm_passthrough_inst_init,
-    .instance_finalize = tpm_passthrough_inst_finalize,
-};
-
-static void tpm_passthrough_register(void)
-{
-    type_register_static(&tpm_passthrough_info);
-}
-
-type_init(tpm_passthrough_register)
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
deleted file mode 100644 (file)
index cfc7572..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * TPM utility functions
- *
- *  Copyright (c) 2010 - 2015 IBM Corporation
- *  Authors:
- *    Stefan Berger <stefanb@us.ibm.com>
- *
- * 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/osdep.h"
-#include "qemu/error-report.h"
-#include "qapi/error.h"
-#include "qapi/visitor.h"
-#include "tpm_int.h"
-#include "exec/memory.h"
-#include "hw/qdev-properties.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/tpm_util.h"
-#include "trace.h"
-
-/* tpm backend property */
-
-static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
-                    Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    TPMBackend **be = qdev_get_prop_ptr(dev, opaque);
-    char *p;
-
-    p = g_strdup(*be ? (*be)->id : "");
-    visit_type_str(v, name, &p, errp);
-    g_free(p);
-}
-
-static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
-                    Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Error *local_err = NULL;
-    Property *prop = opaque;
-    TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
-    char *str;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_str(v, name, &str, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-
-    s = qemu_find_tpm_be(str);
-    if (s == NULL) {
-        error_setg(errp, "Property '%s.%s' can't find value '%s'",
-                   object_get_typename(obj), prop->name, str);
-    } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) {
-        *be = s; /* weak reference, avoid cyclic ref */
-    }
-    g_free(str);
-}
-
-static void release_tpm(Object *obj, const char *name, void *opaque)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    TPMBackend **be = qdev_get_prop_ptr(dev, prop);
-
-    if (*be) {
-        tpm_backend_reset(*be);
-    }
-}
-
-const PropertyInfo qdev_prop_tpm = {
-    .name  = "str",
-    .description = "ID of a tpm to use as a backend",
-    .get   = get_tpm,
-    .set   = set_tpm,
-    .release = release_tpm,
-};
-
-/*
- * Write an error message in the given output buffer.
- */
-void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len)
-{
-    if (out_len >= sizeof(struct tpm_resp_hdr)) {
-        tpm_cmd_set_tag(out, TPM_TAG_RSP_COMMAND);
-        tpm_cmd_set_size(out, sizeof(struct tpm_resp_hdr));
-        tpm_cmd_set_error(out, TPM_FAIL);
-    }
-}
-
-bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
-{
-    if (in_len >= sizeof(struct tpm_req_hdr)) {
-        return tpm_cmd_get_ordinal(in) == TPM_ORD_ContinueSelfTest;
-    }
-
-    return false;
-}
-
-/*
- * Send request to a TPM device. We expect a response within one second.
- */
-static int tpm_util_request(int fd,
-                            const void *request,
-                            size_t requestlen,
-                            void *response,
-                            size_t responselen)
-{
-    fd_set readfds;
-    int n;
-    struct timeval tv = {
-        .tv_sec = 1,
-        .tv_usec = 0,
-    };
-
-    n = write(fd, request, requestlen);
-    if (n < 0) {
-        return -errno;
-    }
-    if (n != requestlen) {
-        return -EFAULT;
-    }
-
-    FD_ZERO(&readfds);
-    FD_SET(fd, &readfds);
-
-    /* wait for a second */
-    n = select(fd + 1, &readfds, NULL, NULL, &tv);
-    if (n != 1) {
-        return -errno;
-    }
-
-    n = read(fd, response, responselen);
-    if (n < sizeof(struct tpm_resp_hdr)) {
-        return -EFAULT;
-    }
-
-    /* check the header */
-    if (tpm_cmd_get_size(response) != n) {
-        return -EMSGSIZE;
-    }
-
-    return 0;
-}
-
-/*
- * A basic test of a TPM device. We expect a well formatted response header
- * (error response is fine).
- */
-static int tpm_util_test(int fd,
-                         const void *request,
-                         size_t requestlen,
-                         uint16_t *return_tag)
-{
-    char buf[1024];
-    ssize_t ret;
-
-    ret = tpm_util_request(fd, request, requestlen,
-                           buf, sizeof(buf));
-    if (ret < 0) {
-        return ret;
-    }
-
-    *return_tag = tpm_cmd_get_tag(buf);
-
-    return 0;
-}
-
-/*
- * Probe for the TPM device in the back
- * Returns 0 on success with the version of the probed TPM set, 1 on failure.
- */
-int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
-{
-    /*
-     * Sending a TPM1.2 command to a TPM2 should return a TPM1.2
-     * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e)
-     *
-     * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the
-     * header.
-     * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag
-     * in the header and an error code.
-     */
-    const struct tpm_req_hdr test_req = {
-        .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
-        .len = cpu_to_be32(sizeof(test_req)),
-        .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
-    };
-
-    const struct tpm_req_hdr test_req_tpm2 = {
-        .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
-        .len = cpu_to_be32(sizeof(test_req_tpm2)),
-        .ordinal = cpu_to_be32(TPM2_CC_ReadClock),
-    };
-    uint16_t return_tag;
-    int ret;
-
-    /* Send TPM 2 command */
-    ret = tpm_util_test(tpm_fd, &test_req_tpm2,
-                        sizeof(test_req_tpm2), &return_tag);
-    /* TPM 2 would respond with a tag of TPM2_ST_NO_SESSIONS */
-    if (!ret && return_tag == TPM2_ST_NO_SESSIONS) {
-        *tpm_version = TPM_VERSION_2_0;
-        return 0;
-    }
-
-    /* Send TPM 1.2 command */
-    ret = tpm_util_test(tpm_fd, &test_req,
-                        sizeof(test_req), &return_tag);
-    if (!ret && return_tag == TPM_TAG_RSP_COMMAND) {
-        *tpm_version = TPM_VERSION_1_2;
-        /* this is a TPM 1.2 */
-        return 0;
-    }
-
-    *tpm_version = TPM_VERSION_UNSPEC;
-
-    return 1;
-}
-
-int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
-                             size_t *buffersize)
-{
-    int ret;
-
-    switch (tpm_version) {
-    case TPM_VERSION_1_2: {
-        const struct tpm_req_get_buffer_size {
-            struct tpm_req_hdr hdr;
-            uint32_t capability;
-            uint32_t len;
-            uint32_t subcap;
-        } QEMU_PACKED tpm_get_buffer_size = {
-            .hdr = {
-                .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
-                .len = cpu_to_be32(sizeof(tpm_get_buffer_size)),
-                .ordinal = cpu_to_be32(TPM_ORD_GetCapability),
-            },
-            .capability = cpu_to_be32(TPM_CAP_PROPERTY),
-            .len = cpu_to_be32(sizeof(uint32_t)),
-            .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER),
-        };
-        struct tpm_resp_get_buffer_size {
-            struct tpm_resp_hdr hdr;
-            uint32_t len;
-            uint32_t buffersize;
-        } QEMU_PACKED tpm_resp;
-
-        ret = tpm_util_request(tpm_fd, &tpm_get_buffer_size,
-                               sizeof(tpm_get_buffer_size),
-                               &tpm_resp, sizeof(tpm_resp));
-        if (ret < 0) {
-            return ret;
-        }
-
-        if (be32_to_cpu(tpm_resp.hdr.len) != sizeof(tpm_resp) ||
-            be32_to_cpu(tpm_resp.len) != sizeof(uint32_t)) {
-            trace_tpm_util_get_buffer_size_hdr_len(
-                be32_to_cpu(tpm_resp.hdr.len),
-                sizeof(tpm_resp));
-            trace_tpm_util_get_buffer_size_len(be32_to_cpu(tpm_resp.len),
-                                               sizeof(uint32_t));
-            error_report("tpm_util: Got unexpected response to "
-                         "TPM_GetCapability; errcode: 0x%x",
-                         be32_to_cpu(tpm_resp.hdr.errcode));
-            return -EFAULT;
-        }
-        *buffersize = be32_to_cpu(tpm_resp.buffersize);
-        break;
-    }
-    case TPM_VERSION_2_0: {
-        const struct tpm2_req_get_buffer_size {
-            struct tpm_req_hdr hdr;
-            uint32_t capability;
-            uint32_t property;
-            uint32_t count;
-        } QEMU_PACKED tpm2_get_buffer_size = {
-            .hdr = {
-                .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
-                .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)),
-                .ordinal = cpu_to_be32(TPM2_CC_GetCapability),
-            },
-            .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES),
-            .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE),
-            .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */
-        };
-        struct tpm2_resp_get_buffer_size {
-            struct tpm_resp_hdr hdr;
-            uint8_t more;
-            uint32_t capability;
-            uint32_t count;
-            uint32_t property1;
-            uint32_t value1;
-            uint32_t property2;
-            uint32_t value2;
-        } QEMU_PACKED tpm2_resp;
-
-        ret = tpm_util_request(tpm_fd, &tpm2_get_buffer_size,
-                               sizeof(tpm2_get_buffer_size),
-                               &tpm2_resp, sizeof(tpm2_resp));
-        if (ret < 0) {
-            return ret;
-        }
-
-        if (be32_to_cpu(tpm2_resp.hdr.len) != sizeof(tpm2_resp) ||
-            be32_to_cpu(tpm2_resp.count) != 2) {
-            trace_tpm_util_get_buffer_size_hdr_len2(
-                be32_to_cpu(tpm2_resp.hdr.len),
-                sizeof(tpm2_resp));
-            trace_tpm_util_get_buffer_size_len2(
-                be32_to_cpu(tpm2_resp.count), 2);
-            error_report("tpm_util: Got unexpected response to "
-                         "TPM2_GetCapability; errcode: 0x%x",
-                         be32_to_cpu(tpm2_resp.hdr.errcode));
-            return -EFAULT;
-        }
-        *buffersize = MAX(be32_to_cpu(tpm2_resp.value1),
-                          be32_to_cpu(tpm2_resp.value2));
-        break;
-    }
-    case TPM_VERSION_UNSPEC:
-        return -EFAULT;
-    }
-
-    trace_tpm_util_get_buffer_size(*buffersize);
-
-    return 0;
-}
-
-void tpm_sized_buffer_reset(TPMSizedBuffer *tsb)
-{
-    g_free(tsb->buffer);
-    tsb->buffer = NULL;
-    tsb->size = 0;
-}
-
-void tpm_util_show_buffer(const unsigned char *buffer,
-                          size_t buffer_size, const char *string)
-{
-    size_t len, i;
-    char *line_buffer, *p;
-
-    if (!trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) {
-        return;
-    }
-    len = MIN(tpm_cmd_get_size(buffer), buffer_size);
-
-    /*
-     * allocate enough room for 3 chars per buffer entry plus a
-     * newline after every 16 chars and a final null terminator.
-     */
-    line_buffer = g_malloc(len * 3 + (len / 16) + 1);
-
-    for (i = 0, p = line_buffer; i < len; i++) {
-        if (i && !(i % 16)) {
-            p += sprintf(p, "\n");
-        }
-        p += sprintf(p, "%.2X ", buffer[i]);
-    }
-    trace_tpm_util_show_buffer(string, len, line_buffer);
-
-    g_free(line_buffer);
-}
index 439e5147870c51b0cc86c1674393b5caef2ae9a9..de9bf1e01b3547101a96337df35616067f514e4d 100644 (file)
@@ -4,38 +4,6 @@
 tpm_crb_mmio_read(uint64_t addr, unsigned size, uint32_t val) "CRB read 0x%016" PRIx64 " len:%u val: 0x%" PRIx32
 tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x%016" PRIx64 " len:%u val: 0x%" PRIx32
 
-# tpm_passthrough.c
-tpm_passthrough_handle_request(void *cmd) "processing command %p"
-tpm_passthrough_reset(void) "reset"
-
-# tpm_util.c
-tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
-tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"
-tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu"
-tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu"
-tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu"
-tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s"
-
-# tpm_emulator.c
-tpm_emulator_set_locality(uint8_t locty) "setting locality to %d"
-tpm_emulator_handle_request(void) "processing TPM command"
-tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64
-tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u"
-tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu"
-tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d"
-tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD"
-tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2"
-tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2"
-tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified"
-tpm_emulator_handle_device_opts_startup_error(void) "Startup error"
-tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x"
-tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x"
-tpm_emulator_set_state_blobs(void) "setting state blobs"
-tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s"
-tpm_emulator_set_state_blobs_done(void) "Done setting state blobs"
-tpm_emulator_pre_save(void) ""
-tpm_emulator_inst_init(void) ""
-
 # tpm_tis.c
 tpm_tis_raise_irq(uint32_t irqmask) "Raising IRQ for flag 0x%08x"
 tpm_tis_new_active_locality(uint8_t locty) "Active locality is now %d"
@@ -56,7 +24,7 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u"
 # tpm_ppi.c
 tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu"
 
-# hw/tpm/tpm_spapr.c
+# tpm_spapr.c
 tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s"
 tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x"
 tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT"
index 298d0eec74d1cc81c4f83760c3a927d86793f673..2e8eb7b94f25d5ab7bb24e9614c7d4cbb9388ba2 100644 (file)
@@ -13,7 +13,7 @@
 #include "qemu/osdep.h"
 #include <glib/gstdio.h>
 
-#include "hw/tpm/tpm_ioctl.h"
+#include "backends/tpm/tpm_ioctl.h"
 #include "io/channel-socket.h"
 #include "qapi/error.h"
 #include "tpm-emu.h"