[{"id":1773737,"web_url":"http://patchwork.ozlabs.org/comment/1773737/","msgid":"<36625c01-a29e-907c-1662-e1ff01e59a43@linux.vnet.ibm.com>","list_archive_url":null,"date":"2017-09-22T16:23:37","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":6671,"url":"http://patchwork.ozlabs.org/api/people/6671/","name":"Stefan Berger","email":"stefanb@linux.vnet.ibm.com"},"content":"On 09/22/2017 08:33 AM, Amarnath Valluri wrote:\n> This change introduces a new TPM backend driver that can communicate with\n> swtpm(software TPM emulator) using unix domain socket interface. QEMU talks to\n> TPM emulator using socket based chardev backend device.\n\ntalks to the TPM emulator using QEMU's socket-based chardev backend device.\n\n>\n> Swtpm uses two Unix sockets for communications, one for plain TPM commands and\n> responses, and one for out-of-band control messages. QEMU passes data socket\n> been used over the control channel.\n\nQEMU passes the data socket to be used over the control channel.\n\nSome comments below. I'll give it a try once we merge the fd passing \ninto swtpm.\n\n\n>\n> The swtpm and associated tools can be found here:\n>      https://github.com/stefanberger/swtpm\n>\n> The swtpm's control channel protocol specification can be found here:\n>      https://github.com/stefanberger/swtpm/wiki/Control-Channel-Specification\n>\n> Usage:\n>      # setup TPM state directory\n>      mkdir /tmp/mytpm\n>      chown -R tss:root /tmp/mytpm\n>      /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek\n>\n>      # Ask qemu to use TPM emulator with given tpm state directory\n>      qemu-system-x86_64 \\\n>          [...] \\\n>          -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \\\n>          -tpmdev emulator,id=tpm0,chardev=chrtpm \\\n>          -device tpm-tis,tpmdev=tpm0 \\\n>          [...]\n>\n> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>\n> ---\n>   configure             |  15 +-\n>   hmp.c                 |   5 +\n>   hw/tpm/Makefile.objs  |   1 +\n>   hw/tpm/tpm_emulator.c | 649 ++++++++++++++++++++++++++++++++++++++++++++++++++\n>   hw/tpm/tpm_ioctl.h    | 246 +++++++++++++++++++\n>   qapi/tpm.json         |  21 +-\n>   qemu-options.hx       |  22 +-\n>   7 files changed, 950 insertions(+), 9 deletions(-)\n>   create mode 100644 hw/tpm/tpm_emulator.c\n>   create mode 100644 hw/tpm/tpm_ioctl.h\n>\n> diff --git a/configure b/configure\n> index cb0f7ed..ce2df2d 100755\n> --- a/configure\n> +++ b/configure\n> @@ -3461,10 +3461,15 @@ fi\n>   ##########################################\n>   # TPM passthrough is only on x86 Linux\n>\n> -if test \"$targetos\" = Linux && test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\n> -  tpm_passthrough=$tpm\n> +if test \"$targetos\" = Linux; then\n> +  tpm_emulator=$tpm\n> +  if test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\n> +    tpm_passthrough=$tpm\n> +  else\n> +    tpm_passthrough=no\n> +  fi\n>   else\n> -  tpm_passthrough=no\n> +  tpm_emulator=no\n>   fi\n>\n>   ##########################################\n> @@ -5359,6 +5364,7 @@ echo \"gcov enabled      $gcov\"\n>   echo \"TPM support       $tpm\"\n>   echo \"libssh2 support   $libssh2\"\n>   echo \"TPM passthrough   $tpm_passthrough\"\n> +echo \"TPM emulator      $tpm_emulator\"\n>   echo \"QOM debugging     $qom_cast_debug\"\n>   echo \"Live block migration $live_block_migration\"\n>   echo \"lzo support       $lzo\"\n> @@ -5943,6 +5949,9 @@ if test \"$tpm\" = \"yes\"; then\n>     if test \"$tpm_passthrough\" = \"yes\"; then\n>       echo \"CONFIG_TPM_PASSTHROUGH=y\" >> $config_host_mak\n>     fi\n> +  if test \"$tpm_emulator\" = \"yes\"; then\n> +    echo \"CONFIG_TPM_EMULATOR=y\" >> $config_host_mak\n> +  fi\n>   fi\n>\n>   echo \"TRACE_BACKENDS=$trace_backends\" >> $config_host_mak\n> diff --git a/hmp.c b/hmp.c\n> index cf62b2e..7e69eca 100644\n> --- a/hmp.c\n> +++ b/hmp.c\n> @@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)\n>       Error *err = NULL;\n>       unsigned int c = 0;\n>       TPMPassthroughOptions *tpo;\n> +    TPMEmulatorOptions *teo;\n>\n>       info_list = qmp_query_tpm(&err);\n>       if (err) {\n> @@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)\n>                              tpo->has_cancel_path ? \",cancel-path=\" : \"\",\n>                              tpo->has_cancel_path ? tpo->cancel_path : \"\");\n>               break;\n> +        case TPM_TYPE_EMULATOR:\n> +            teo = ti->options->u.emulator.data;\n> +            monitor_printf(mon, \",chardev=%s\", teo->chardev);\n> +            break;\n>           case TPM_TYPE__MAX:\n>               break;\n>           }\n> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs\n> index 64cecc3..41f0b7a 100644\n> --- a/hw/tpm/Makefile.objs\n> +++ b/hw/tpm/Makefile.objs\n> @@ -1,2 +1,3 @@\n>   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o\n>   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o\n> +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o\n> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c\n> new file mode 100644\n> index 0000000..c02bbe2\n> --- /dev/null\n> +++ b/hw/tpm/tpm_emulator.c\n> @@ -0,0 +1,649 @@\n> +/*\n> + *  emulator TPM driver\n\nEmulator\n\n> + *\n> + *  Copyright (c) 2017 Intel Corporation\n> + *  Author: Amarnath Valluri <amarnath.valluri@intel.com>\n> + *\n> + *  Copyright (c) 2010 - 2013 IBM Corporation\n> + *  Authors:\n> + *    Stefan Berger <stefanb@us.ibm.com>\n> + *\n> + *  Copyright (C) 2011 IAIK, Graz University of Technology\n> + *    Author: Andreas Niederl\n> + *\n> + * This library is free software; you can redistribute it and/or\n> + * modify it under the terms of the GNU Lesser General Public\n> + * License as published by the Free Software Foundation; either\n> + * version 2 of the License, or (at your option) any later version.\n> + *\n> + * This library is distributed in the hope that it will be useful,\n> + * but WITHOUT ANY WARRANTY; without even the implied warranty of\n> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n> + * Lesser General Public License for more details.\n> + *\n> + * You should have received a copy of the GNU Lesser General Public\n> + * License along with this library; if not, see <http://www.gnu.org/licenses/>\n> + *\n> + */\n> +\n> +#include \"qemu/osdep.h\"\n> +#include \"qemu/error-report.h\"\n> +#include \"qemu/sockets.h\"\n> +#include \"io/channel-socket.h\"\n> +#include \"sysemu/tpm_backend.h\"\n> +#include \"tpm_int.h\"\n> +#include \"hw/hw.h\"\n> +#include \"hw/i386/pc.h\"\n> +#include \"tpm_util.h\"\n> +#include \"tpm_ioctl.h\"\n> +#include \"migration/blocker.h\"\n> +#include \"qapi/error.h\"\n> +#include \"chardev/char-fe.h\"\n> +\n> +#include <fcntl.h>\n> +#include <sys/types.h>\n> +#include <sys/stat.h>\n> +#include <stdio.h>\n> +\n> +#define DEBUG_TPM 0\n> +\n> +#define DPRINT(fmt, ...) do { \\\n> +    if (DEBUG_TPM) { \\\n> +        fprintf(stderr, fmt, ## __VA_ARGS__); \\\n> +    } \\\n> +} while (0);\n> +\n> +#define DPRINTF(fmt, ...) DPRINT(\"tpm-emulator: \"fmt\"\\n\", __VA_ARGS__)\n> +\n> +#define TYPE_TPM_EMULATOR \"tpm-emulator\"\n> +#define TPM_EMULATOR(obj) \\\n> +    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)\n> +\n> +#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))\n> +\n> +static const TPMDriverOps tpm_emulator_driver;\n> +\n> +/* data structures */\n> +typedef struct TPMEmulator {\n> +    TPMBackend parent;\n> +\n> +    TPMEmulatorOptions *options;\n> +    CharBackend ctrl_dev;\n> +    QIOChannel *data_ioc;\n> +    bool op_executing;\n> +    bool op_canceled;\n> +    bool had_startup_error;\n> +    TPMVersion tpm_version;\n> +    ptm_cap caps; /* capabilities of the TPM */\n> +    uint8_t cur_locty_number; /* last set locality */\n> +    QemuMutex state_lock;\n> +    Error *migration_blocker;\n> +} TPMEmulator;\n> +\n> +\n> +static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long cmd, void *msg,\n> +                                size_t msg_len_in, size_t msg_len_out)\n> +{\n> +    uint32_t cmd_no = cpu_to_be32(cmd);\n> +    ssize_t n = sizeof(uint32_t) + msg_len_in;\n> +    uint8_t *buf = NULL;\n> +\n> +    buf = (uint8_t *)malloc(n);\n> +    memcpy(buf, &cmd_no, sizeof(cmd_no));\n> +    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);\n> +\n> +    n += qemu_chr_fe_write_all(dev, (const uint8_t *)buf, n);\n> +    free(buf);\n> +\n> +    if (n > 0) {\n> +        if (msg_len_out > 0) {\n> +            n = qemu_chr_fe_read_all(dev, (uint8_t *)msg, msg_len_out);\n> +            /* simulate ioctl return value */\n> +            if (n > 0) {\n> +                n = 0;\n> +            }\n> +        } else {\n> +            n = 0;\n> +        }\n> +    }\n> +    return n;\n> +}\n> +\n> +static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,\n> +                                     const uint8_t *in, uint32_t in_len,\n> +                                     uint8_t *out, uint32_t out_len,\n> +                                     bool *selftest_done)\n> +{\n> +    ssize_t ret;\n> +    bool is_selftest = false;\n> +    const struct tpm_resp_hdr *hdr = NULL;\n> +    Error *err = NULL;\n> +\n> +    tpm_pt->op_canceled = false;\n> +    tpm_pt->op_executing = true;\n\nadd an empty line after the above\n\n> +    if (selftest_done) {\n> +        *selftest_done = false;\n> +        is_selftest = tpm_util_is_selftest(in, in_len);\n> +    }\n> +\n> +    ret = qio_channel_write(tpm_pt->data_ioc, (char *)in, in_len, &err);\n> +    if (ret != in_len || err) {\n> +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n> +            error_report(\"tpm-emulator: error while transmitting data \"\n> +                         \"to TPM: %s\", err ? error_get_pretty(err) : \"\");\n> +            error_free(err);\n> +        }\n> +        goto err_exit;\n> +    }\n> +\n> +    tpm_pt->op_executing = false;\n> +\n> +    ret = qio_channel_read(tpm_pt->data_ioc, (char *)out, out_len, &err);\n> +    if (ret < 0 || err) {\n> +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n> +            error_report(\"tpm-emulator: error while reading data from \"\n> +                         \"TPM: %s\", err ? error_get_pretty(err) : \"\");\n> +            error_free(err);\n> +        }\n> +    } else if (ret >= sizeof(*hdr)) {\n> +        hdr = (struct tpm_resp_hdr *)out;\n> +    }\n> +\n> +    if (!hdr || be32_to_cpu(hdr->len) != ret) {\n> +        error_report(\"tpm-emulator: received invalid response \"\n> +                     \"packet from TPM with length :%ld\", ret);\n> +        ret = -1;\n> +        goto err_exit;\n> +    }\n> +\n> +    if (is_selftest) {\n> +        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);\n> +    }\n> +\n> +    return 0;\n> +\n> +err_exit:\n> +    if (ret < 0) {\n> +        tpm_util_write_fatal_error_response(out, out_len);\n> +    }\n> +\n> +    tpm_pt->op_executing = false;\n> +\n> +    return ret;\n> +}\n> +\n> +static int tpm_emulator_set_locality(TPMEmulator *tpm_pt, uint8_t locty_number)\n> +{\n> +    ptm_loc loc;\n> +\n> +    DPRINTF(\"%s : locality: 0x%x\", __func__, locty_number);\n> +\n> +    if (tpm_pt->cur_locty_number != locty_number) {\n> +        DPRINTF(\"setting locality : 0x%x\", locty_number);\n> +        loc.u.req.loc = locty_number;\n> +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_LOCALITY, &loc,\n> +                             sizeof(loc), sizeof(loc)) < 0) {\n> +            error_report(\"tpm-emulator: could not set locality : %s\",\n> +                         strerror(errno));\n> +            return -1;\n> +        }\n> +        loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);\n> +        if (loc.u.resp.tpm_result != 0) {\n> +            error_report(\"tpm-emulator: TPM result for set locality : 0x%x\",\n> +                         loc.u.resp.tpm_result);\n> +            return -1;\n> +        }\n> +        tpm_pt->cur_locty_number = locty_number;\n> +    }\n> +    return 0;\n> +}\n> +\n> +static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    TPMLocality *locty = NULL;\n> +    bool selftest_done = false;\n> +\n> +    DPRINTF(\"processing command type %d\", cmd);\n> +\n> +    switch (cmd) {\n> +    case TPM_BACKEND_CMD_PROCESS_CMD:\n> +        qemu_mutex_lock(&tpm_pt->state_lock);\n> +        locty = tb->tpm_state->locty_data;\n> +        if (tpm_emulator_set_locality(tpm_pt,\n> +                                      tb->tpm_state->locty_number) < 0) {\n> +            tpm_util_write_fatal_error_response(locty->r_buffer.buffer,\n> +                                           locty->r_buffer.size);\n> +        } else {\n> +            tpm_emulator_unix_tx_bufs(tpm_pt, locty->w_buffer.buffer,\n> +                                              locty->w_offset,\n> +                                              locty->r_buffer.buffer,\n> +                                              locty->r_buffer.size,\n> +                                              &selftest_done);\n> +        }\n> +\n> +        tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,\n> +                               selftest_done);\n> +        qemu_mutex_unlock(&tpm_pt->state_lock);\n> +\n> +        break;\n> +    case TPM_BACKEND_CMD_INIT:\n> +    case TPM_BACKEND_CMD_END:\n> +    case TPM_BACKEND_CMD_TPM_RESET:\n> +        /* nothing to do */\n> +        break;\n> +    }\n> +}\n> +\n> +/*\n> + * Gracefully shut down the external unixio TPM\n> + */\n> +static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)\n> +{\n> +    ptm_res res;\n> +\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SHUTDOWN, &res, 0,\n> +                         sizeof(res)) < 0) {\n> +        error_report(\"tpm-emulator: Could not cleanly shutdown the TPM: %s\",\n> +                     strerror(errno));\n> +    } else if (res != 0) {\n> +        error_report(\"tpm-emulator: TPM result for sutdown: 0x%x\",\n> +                     be32_to_cpu(res));\n> +    }\n> +}\n> +\n> +static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)\n> +{\n> +    DPRINTF(\"%s\", __func__);\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_GET_CAPABILITY,\n> +                         &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) < 0) {\n> +        error_report(\"tpm-emulator: probing failed : %s\", strerror(errno));\n> +        return -1;\n> +    }\n> +\n> +    tpm_pt->caps = be64_to_cpu(tpm_pt->caps);\n> +\n> +    DPRINTF(\"capbilities : 0x%lx\", tpm_pt->caps);\n> +\n> +    return 0;\n> +}\n> +\n> +static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)\n> +{\n> +    ptm_cap caps = 0;\n> +    const char *tpm = NULL;\n> +\n> +    /* check for min. required capabilities */\n> +    switch (tpm_pt->tpm_version) {\n> +    case TPM_VERSION_1_2:\n> +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |\n> +               PTM_CAP_SET_LOCALITY;\n> +        tpm = \"1.2\";\n> +        break;\n> +    case TPM_VERSION_2_0:\n> +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |\n> +               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED;\n\nSince you are passing the data channel file descriptor via the new \ncommand, you should be checking for that new command here as well. Add \nit to both 'caps'.\n\n> +        tpm = \"2\";\n> +        break;\n> +    case TPM_VERSION_UNSPEC:\n> +        error_report(\"tpm-emulator: TPM version has not been set\");\n> +        return -1;\n> +    }\n> +\n> +    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {\n> +        error_report(\"tpm-emulator: TPM does not implement minimum set of \"\n> +                     \"required capabilities for TPM %s (0x%x)\", tpm, (int)caps);\n> +        return -1;\n> +    }\n> +\n> +    return 0;\n> +}\n> +\n> +static int tpm_emulator_startup_tpm(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_init init;\n> +    ptm_res res;\n> +\n> +    DPRINTF(\"%s\", __func__);\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_INIT, &init, sizeof(init),\n> +                         sizeof(init)) < 0) {\n> +        error_report(\"tpm-emulator: could not send INIT: %s\",\n> +                     strerror(errno));\n> +        goto err_exit;\n> +    }\n> +\n> +    res = be32_to_cpu(init.u.resp.tpm_result);\n> +    if (res) {\n> +        error_report(\"tpm-emulator: TPM result for CMD_INIT: 0x%x\", res);\n> +        goto err_exit;\n> +    }\n> +    return 0;\n> +\n> +err_exit:\n> +    tpm_pt->had_startup_error = true;\n> +    return -1;\n> +}\n> +\n> +static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_est est;\n> +\n> +    DPRINTF(\"%s\", __func__);\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_GET_TPMESTABLISHED, &est, 0,\n> +                         sizeof(est)) < 0) {\n> +        error_report(\"tpm-emulator: Could not get the TPM established flag: %s\",\n> +                     strerror(errno));\n> +        return false;\n> +    }\n> +    DPRINTF(\"established flag: %0x\", est.u.resp.bit);\n> +\n> +    return (est.u.resp.bit != 0);\n> +}\n> +\n> +static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,\n> +                                                   uint8_t locty)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_reset_est reset_est;\n> +    ptm_res res;\n> +\n> +    /* only a TPM 2.0 will support this */\n> +    if (tpm_pt->tpm_version == TPM_VERSION_2_0) {\n> +        reset_est.u.req.loc = tpm_pt->cur_locty_number;\n> +\n> +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_RESET_TPMESTABLISHED,\n> +                                 &reset_est, sizeof(reset_est),\n> +                                 sizeof(reset_est)) < 0) {\n> +            error_report(\"tpm-emulator: Could not reset the establishment bit: \"\n> +                          \"%s\", strerror(errno));\n> +            return -1;\n> +        }\n> +\n> +        res = be32_to_cpu(reset_est.u.resp.tpm_result);\n> +        if (res) {\n> +            error_report(\"tpm-emulator: TPM result for rest establixhed flag: \"\n> +                         \"0x%x\", res);\n> +            return -1;\n> +        }\n> +    }\n> +\n> +    return 0;\n> +}\n> +\n> +static bool tpm_emulator_had_startup_error(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +\n> +    return tpm_pt->had_startup_error;\n> +}\n> +\n> +static void tpm_emulator_cancel_cmd(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_res res;\n> +\n> +    /*\n> +     * As of Linux 3.7 the tpm_tis driver does not properly cancel\n> +     * commands on all TPM manufacturers' TPMs.\n> +     * Only cancel if we're busy so we don't cancel someone else's\n> +     * command, e.g., a command executed on the host.\n> +     */\n> +    if (tpm_pt->op_executing) {\n> +        if (TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, PTM_CAP_CANCEL_TPM_CMD)) {\n> +            if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_CANCEL_TPM_CMD,\n> +                                     &res, 0, sizeof(res)) < 0) {\n> +                error_report(\"tpm-emulator: Could not cancel command: %s\",\n> +                             strerror(errno));\n> +            } else if (res != 0) {\n> +                error_report(\"tpm-emulator: Failed to cancel TPM: 0x%x\",\n> +                             be32_to_cpu(res));\n> +            } else {\n> +                tpm_pt->op_canceled = true;\n> +            }\n> +        }\n> +    }\n> +}\n> +\n> +static void tpm_emulator_reset(TPMBackend *tb)\n> +{\n> +    DPRINTF(\"%s\", __func__);\n> +\n> +    tpm_emulator_cancel_cmd(tb);\n> +}\n> +\n> +static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +\n> +    return tpm_pt->tpm_version;\n> +}\n> +\n> +static void tpm_emulator_block_migration(TPMEmulator *tpm_pt)\n> +{\n> +    Error *err = NULL;\n> +\n> +    error_setg(&tpm_pt->migration_blocker,\n> +               \"Migration disabled: TPM emulator not yet migratable\");\n> +    migrate_add_blocker(tpm_pt->migration_blocker, &err);\n> +    if (err) {\n> +        error_free(err);\n> +        error_free(tpm_pt->migration_blocker);\n> +        tpm_pt->migration_blocker = NULL;\n> +    }\n> +}\n> +\n> +static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_pt)\n> +{\n> +    ptm_res res;\n> +    Error *err = NULL;\n> +    int fds[2] = { -1, -1 };\n> +\n> +    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {\n> +        error_report(\"tpm-emulator: Failed to create socketpair\");\n> +        return -1;\n> +    }\n> +\n> +    qemu_chr_fe_set_msgfds(&tpm_pt->ctrl_dev, fds + 1, 1);\n> +\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_DATAFD, &res, 0,\n> +                    sizeof(res)) || res != 0) {\n> +        error_report(\"tpm-emulator: Failed to send CMD_SET_DATAFD: %s\",\n> +                     strerror(errno));\n> +        goto err_exit;\n> +    }\n> +\n> +    tpm_pt->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));\n> +    if (err) {\n> +        error_report(\"tpm-emulator: Failed to create io channel : %s\",\n> +                       error_get_pretty(err));\n> +        error_free(err);\n> +        goto err_exit;\n> +    }\n> +\n> +    return 0;\n> +\n> +err_exit:\n> +    closesocket(fds[0]);\n> +    closesocket(fds[1]);\n> +    return -1;\n> +}\n> +\n> +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt, QemuOpts *opts)\n> +{\n> +    const char *value;\n> +\n> +    value = qemu_opt_get(opts, \"chardev\");\n> +    if (value) {\n> +        Error *err = NULL;\n> +        Chardev *dev = qemu_chr_find(value);\n> +\n> +        tpm_pt->options->chardev = g_strdup(value);\n\nCould you set this after the error checks?\n\n> +\n> +        if (!dev || !qemu_chr_fe_init(&tpm_pt->ctrl_dev, dev, &err)) {\n> +            error_report(\"tpm-emulator: No valid chardev found at '%s': %s\",\n> +                         value, err ? error_get_pretty(err) : \"\");\n> +            error_free(err);\n> +            goto err;\n> +        }\n> +    }\n> +\n> +    if (tpm_emulator_prepare_data_fd(tpm_pt) < 0) {\n> +        goto err;\n> +    }\n> +\n> +    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used\n> +     * by passthrough driver, which not yet using GIOChannel.\n> +     */\n> +    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_pt->data_ioc)->fd,\n> +                             &tpm_pt->tpm_version)) {\n> +        error_report(\"'%s' is not emulating TPM device. Error: %s\",\n> +                      tpm_pt->options->chardev, strerror(errno));\n> +        goto err;\n> +    }\n> +\n> +    DPRINTF(\"TPM Version %s\", tpm_pt->tpm_version == TPM_VERSION_1_2 ? \"1.2\" :\n> +             (tpm_pt->tpm_version == TPM_VERSION_2_0 ?  \"2.0\" : \"Unspecified\"));\n> +\n> +    if (tpm_emulator_probe_caps(tpm_pt) ||\n> +        tpm_emulator_check_caps(tpm_pt)) {\n> +        goto err;\n> +    }\n> +\n> +    tpm_emulator_block_migration(tpm_pt);\n> +\n> +    return 0;\n> +\n> +err:\n> +    DPRINT(\"Startup error\\n\");\n> +    return -1;\n> +}\n> +\n> +static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)\n> +{\n> +    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));\n> +\n> +    tb->id = g_strdup(id);\n> +\n> +    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {\n> +        goto err_exit;\n> +    }\n> +\n> +    return tb;\n> +\n> +err_exit:\n> +    object_unref(OBJECT(tb));\n> +\n> +    return NULL;\n> +}\n> +\n> +static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    TpmTypeOptions *options = NULL;\n> +    TPMEmulatorOptions *eoptions = NULL;\n> +\n> +    eoptions = g_new0(TPMEmulatorOptions, 1);\n> +    if (!eoptions) {\n> +        return NULL;\n> +    }\n> +    DPRINTF(\"%s\", __func__);\n\nYou can probably remove this.\n\n> +\n> +    eoptions->chardev = g_strdup(tpm_pt->options->chardev);\n> +    options = g_new0(TpmTypeOptions, 1);\n> +    if (!options) {\n> +        qapi_free_TPMEmulatorOptions(eoptions);\n> +        return NULL;\n> +    }\n> +\n> +    options->type = TPM_TYPE_EMULATOR;\n> +    options->u.emulator.data = eoptions;\n> +\n> +    return options;\n> +}\n> +\n> +static const QemuOptDesc tpm_emulator_cmdline_opts[] = {\n> +    TPM_STANDARD_CMDLINE_OPTS,\n> +    {\n> +        .name = \"chardev\",\n> +        .type = QEMU_OPT_STRING,\n> +        .help = \"Character device to use for out-of-band control messages\",\n> +    },\n> +    { /* end of list */ },\n> +};\n> +\n> +static const TPMDriverOps tpm_emulator_driver = {\n> +    .type                     = TPM_TYPE_EMULATOR,\n> +    .opts                     = tpm_emulator_cmdline_opts,\n> +    .desc                     = \"TPM emulator backend driver\",\n> +\n> +    .create                   = tpm_emulator_create,\n> +    .startup_tpm              = tpm_emulator_startup_tpm,\n> +    .reset                    = tpm_emulator_reset,\n> +    .had_startup_error        = tpm_emulator_had_startup_error,\n> +    .cancel_cmd               = tpm_emulator_cancel_cmd,\n> +    .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,\n> +    .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,\n> +    .get_tpm_version          = tpm_emulator_get_tpm_version,\n> +    .get_tpm_options          = tpm_emulator_get_tpm_options,\n> +};\n> +\n> +static void tpm_emulator_inst_init(Object *obj)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n> +\n> +    DPRINTF(\"%s\", __func__);\n> +    tpm_pt->options = g_new0(TPMEmulatorOptions, 1);\n> +    tpm_pt->op_executing = tpm_pt->op_canceled = false;\n> +    tpm_pt->had_startup_error = false;\n> +    tpm_pt->cur_locty_number = ~0;\n> +    qemu_mutex_init(&tpm_pt->state_lock);\n> +}\n> +\n> +static void tpm_emulator_inst_finalize(Object *obj)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n> +\n> +    tpm_emulator_cancel_cmd(TPM_BACKEND(obj));\n> +    tpm_emulator_shutdown(tpm_pt);\n> +\n> +    if (tpm_pt->data_ioc) {\n> +        qio_channel_close(tpm_pt->data_ioc, NULL);\n> +    }\n> +\n> +    qemu_chr_fe_deinit(&tpm_pt->ctrl_dev, false);\n> +\n> +    if (tpm_pt->options) {\n> +        qapi_free_TPMEmulatorOptions(tpm_pt->options);\n> +    }\n> +\n> +    if (tpm_pt->migration_blocker) {\n> +        migrate_del_blocker(tpm_pt->migration_blocker);\n> +        error_free(tpm_pt->migration_blocker);\n> +    }\n> +}\n> +\n> +static void tpm_emulator_class_init(ObjectClass *klass, void *data)\n> +{\n> +    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);\n> +    tbc->ops = &tpm_emulator_driver;\n> +    tbc->handle_request = tpm_emulator_handle_request;\n> +}\n> +\n> +static const TypeInfo tpm_emulator_info = {\n> +    .name = TYPE_TPM_EMULATOR,\n> +    .parent = TYPE_TPM_BACKEND,\n> +    .instance_size = sizeof(TPMEmulator),\n> +    .class_init = tpm_emulator_class_init,\n> +    .instance_init = tpm_emulator_inst_init,\n> +    .instance_finalize = tpm_emulator_inst_finalize,\n> +};\n> +\n> +static void tpm_emulator_register(void)\n> +{\n> +    type_register_static(&tpm_emulator_info);\n> +    tpm_register_driver(&tpm_emulator_driver);\n> +}\n> +\n> +type_init(tpm_emulator_register)\n> diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h\n> new file mode 100644\n> index 0000000..33564b1\n> --- /dev/null\n> +++ b/hw/tpm/tpm_ioctl.h\n> @@ -0,0 +1,246 @@\n> +/*\n> + * tpm_ioctl.h\n> + *\n> + * (c) Copyright IBM Corporation 2014, 2015.\n> + *\n> + * This file is licensed under the terms of the 3-clause BSD license\n> + */\n> +#ifndef _TPM_IOCTL_H_\n> +#define _TPM_IOCTL_H_\n> +\n> +#include <stdint.h>\n> +#include <sys/uio.h>\n> +#include <sys/types.h>\n> +#include <sys/ioctl.h>\n> +\n> +/*\n> + * Every response from a command involving a TPM command execution must hold\n> + * the ptm_res as the first element.\n> + * ptm_res corresponds to the error code of a command executed by the TPM.\n> + */\n> +\n> +typedef uint32_t ptm_res;\n> +\n> +/* PTM_GET_TPMESTABLISHED: get the establishment bit */\n> +struct ptm_est {\n> +    union {\n> +        struct {\n> +            ptm_res tpm_result;\n> +            unsigned char bit; /* TPM established bit */\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* PTM_RESET_TPMESTABLISHED: reset establishment bit */\n> +struct ptm_reset_est {\n> +    union {\n> +        struct {\n> +            uint8_t loc; /* locality to use */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* PTM_INIT */\n> +struct ptm_init {\n> +    union {\n> +        struct {\n> +            uint32_t init_flags; /* see definitions below */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* above init_flags */\n> +#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)\n> +    /* delete volatile state file after reading it */\n> +\n> +/* PTM_SET_LOCALITY */\n> +struct ptm_loc {\n> +    union {\n> +        struct {\n> +            uint8_t loc; /* locality to set */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* PTM_HASH_DATA: hash given data */\n> +struct ptm_hdata {\n> +    union {\n> +        struct {\n> +            uint32_t length;\n> +            uint8_t data[4096];\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/*\n> + * size of the TPM state blob to transfer; x86_64 can handle 8k,\n> + * ppc64le only ~7k; keep the response below a 4k page size\n> + */\n> +#define PTM_STATE_BLOB_SIZE (3 * 1024)\n> +\n> +/*\n> + * The following is the data structure to get state blobs from the TPM.\n> + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads\n> + * with this ioctl and with adjusted offset are necessary. All bytes\n> + * must be transferred and the transfer is done once the last byte has been\n> + * returned.\n> + * It is possible to use the read() interface for reading the data; however, the\n> + * first bytes of the state blob will be part of the response to the ioctl(); a\n> + * subsequent read() is only necessary if the total length (totlength) exceeds\n> + * the number of received bytes. seek() is not supported.\n> + */\n> +struct ptm_getstate {\n> +    union {\n> +        struct {\n> +            uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */\n> +            uint32_t type;        /* which blob to pull */\n> +            uint32_t offset;      /* offset from where to read */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +            uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */\n> +            uint32_t totlength;   /* total length that will be transferred */\n> +            uint32_t length;      /* number of bytes in following buffer */\n> +            uint8_t  data[PTM_STATE_BLOB_SIZE];\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* TPM state blob types */\n> +#define PTM_BLOB_TYPE_PERMANENT  1\n> +#define PTM_BLOB_TYPE_VOLATILE   2\n> +#define PTM_BLOB_TYPE_SAVESTATE  3\n> +\n> +/* state_flags above : */\n> +#define PTM_STATE_FLAG_DECRYPTED     1 /* on input:  get decrypted state */\n> +#define PTM_STATE_FLAG_ENCRYPTED     2 /* on output: state is encrypted */\n> +\n> +/*\n> + * The following is the data structure to set state blobs in the TPM.\n> + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple\n> + * 'writes' using this ioctl are necessary. The last packet is indicated\n> + * by the length being smaller than the PTM_STATE_BLOB_SIZE.\n> + * The very first packet may have a length indicator of '0' enabling\n> + * a write() with all the bytes from a buffer. If the write() interface\n> + * is used, a final ioctl with a non-full buffer must be made to indicate\n> + * that all data were transferred (a write with 0 bytes would not work).\n> + */\n> +struct ptm_setstate {\n> +    union {\n> +        struct {\n> +            uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */\n> +            uint32_t type;        /* which blob to set */\n> +            uint32_t length;      /* length of the data;\n> +                                     use 0 on the first packet to\n> +                                     transfer using write() */\n> +            uint8_t data[PTM_STATE_BLOB_SIZE];\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/*\n> + * PTM_GET_CONFIG: Data structure to get runtime configuration information\n> + * such as which keys are applied.\n> + */\n> +struct ptm_getconfig {\n> +    union {\n> +        struct {\n> +            ptm_res tpm_result;\n> +            uint32_t flags;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +#define PTM_CONFIG_FLAG_FILE_KEY        0x1\n> +#define PTM_CONFIG_FLAG_MIGRATION_KEY   0x2\n> +\n> +\n> +typedef uint64_t ptm_cap;\n> +typedef struct ptm_est ptm_est;\n> +typedef struct ptm_reset_est ptm_reset_est;\n> +typedef struct ptm_loc ptm_loc;\n> +typedef struct ptm_hdata ptm_hdata;\n> +typedef struct ptm_init ptm_init;\n> +typedef struct ptm_getstate ptm_getstate;\n> +typedef struct ptm_setstate ptm_setstate;\n> +typedef struct ptm_getconfig ptm_getconfig;\n> +\n> +/* capability flags returned by PTM_GET_CAPABILITY */\n> +#define PTM_CAP_INIT               (1)\n> +#define PTM_CAP_SHUTDOWN           (1 << 1)\n> +#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)\n> +#define PTM_CAP_SET_LOCALITY       (1 << 3)\n> +#define PTM_CAP_HASHING            (1 << 4)\n> +#define PTM_CAP_CANCEL_TPM_CMD     (1 << 5)\n> +#define PTM_CAP_STORE_VOLATILE     (1 << 6)\n> +#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)\n> +#define PTM_CAP_GET_STATEBLOB      (1 << 8)\n> +#define PTM_CAP_SET_STATEBLOB      (1 << 9)\n> +#define PTM_CAP_STOP               (1 << 10)\n> +#define PTM_CAP_GET_CONFIG         (1 << 11)\n> +#define PTM_CAP_SET_DATAFD         (1 << 12)\n> +\n> +enum {\n> +    PTM_GET_CAPABILITY     = _IOR('P', 0, ptm_cap),\n> +    PTM_INIT               = _IOWR('P', 1, ptm_init),\n> +    PTM_SHUTDOWN           = _IOR('P', 2, ptm_res),\n> +    PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),\n> +    PTM_SET_LOCALITY       = _IOWR('P', 4, ptm_loc),\n> +    PTM_HASH_START         = _IOR('P', 5, ptm_res),\n> +    PTM_HASH_DATA          = _IOWR('P', 6, ptm_hdata),\n> +    PTM_HASH_END           = _IOR('P', 7, ptm_res),\n> +    PTM_CANCEL_TPM_CMD     = _IOR('P', 8, ptm_res),\n> +    PTM_STORE_VOLATILE     = _IOR('P', 9, ptm_res),\n> +    PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),\n> +    PTM_GET_STATEBLOB      = _IOWR('P', 11, ptm_getstate),\n> +    PTM_SET_STATEBLOB      = _IOWR('P', 12, ptm_setstate),\n> +    PTM_STOP               = _IOR('P', 13, ptm_res),\n> +    PTM_GET_CONFIG         = _IOR('P', 14, ptm_getconfig),\n> +    PTM_SET_DATAFD         = _IOR('P', 15, ptm_res),\n> +};\n> +\n> +/*\n> + * Commands used by the non-CUSE TPMs\n> + *\n> + * All messages container big-endian data.\n> + *\n> + * The return messages only contain the 'resp' part of the unions\n> + * in the data structures above. Besides that the limits in the\n> + * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data\n> + * and ptm_set_state:u.req.data) are 0xffffffff.\n> + */\n> +enum {\n> +    CMD_GET_CAPABILITY = 1,\n> +    CMD_INIT,\n> +    CMD_SHUTDOWN,\n> +    CMD_GET_TPMESTABLISHED,\n> +    CMD_SET_LOCALITY,\n> +    CMD_HASH_START,\n> +    CMD_HASH_DATA,\n> +    CMD_HASH_END,\n> +    CMD_CANCEL_TPM_CMD,\n> +    CMD_STORE_VOLATILE,\n> +    CMD_RESET_TPMESTABLISHED,\n> +    CMD_GET_STATEBLOB,\n> +    CMD_SET_STATEBLOB,\n> +    CMD_STOP,\n> +    CMD_GET_CONFIG,\n> +    CMD_SET_DATAFD\n> +};\n> +\n> +#endif /* _TPM_IOCTL_H */\n> diff --git a/qapi/tpm.json b/qapi/tpm.json\n> index e8b2d8d..7093f26 100644\n> --- a/qapi/tpm.json\n> +++ b/qapi/tpm.json\n> @@ -39,10 +39,12 @@\n>   # An enumeration of TPM types\n>   #\n>   # @passthrough: TPM passthrough type\n> +# @emulator: Software Emulator TPM type\n> +#            Since: 2.11\n>   #\n>   # Since: 1.5\n>   ##\n> -{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }\n> +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }\n>\n>   ##\n>   # @query-tpm-types:\n> @@ -56,7 +58,7 @@\n>   # Example:\n>   #\n>   # -> { \"execute\": \"query-tpm-types\" }\n> -# <- { \"return\": [ \"passthrough\" ] }\n> +# <- { \"return\": [ \"passthrough\", \"emulator\" ] }\n>   #\n>   ##\n>   { 'command': 'query-tpm-types', 'returns': ['TpmType'] }\n> @@ -77,16 +79,29 @@\n>                                                '*cancel-path' : 'str'} }\n>\n>   ##\n> +# @TPMEmulatorOptions:\n> +#\n> +# Information about the TPM emulator type\n> +#\n> +# @chardev: Name of a unix socket chardev\n> +#\n> +# Since: 2.11\n> +##\n> +{ 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' } }\n> +\n> +##\n>   # @TpmTypeOptions:\n>   #\n>   # A union referencing different TPM backend types' configuration options\n>   #\n>   # @type: 'passthrough' The configuration options for the TPM passthrough type\n> +#        'emulator' The configuration options for TPM emulator backend type\n>   #\n>   # Since: 1.5\n>   ##\n>   { 'union': 'TpmTypeOptions',\n> -   'data': { 'passthrough' : 'TPMPassthroughOptions' } }\n> +   'data': { 'passthrough' : 'TPMPassthroughOptions',\n> +             'emulator': 'TPMEmulatorOptions' } }\n>\n>   ##\n>   # @TPMInfo:\n> diff --git a/qemu-options.hx b/qemu-options.hx\n> index 77859a2..1e93e53 100644\n> --- a/qemu-options.hx\n> +++ b/qemu-options.hx\n> @@ -3121,7 +3121,9 @@ DEF(\"tpmdev\", HAS_ARG, QEMU_OPTION_tpmdev, \\\n>       \"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\\n\"\n>       \"                use path to provide path to a character device; default is /dev/tpm0\\n\"\n>       \"                use cancel-path to provide path to TPM's cancel sysfs entry; if\\n\"\n> -    \"                not provided it will be searched for in /sys/class/misc/tpm?/device\\n\",\n> +    \"                not provided it will be searched for in /sys/class/misc/tpm?/device\\n\"\n> +    \"-tpmdev emulator,id=id,chardev=dev\\n\"\n> +    \"                configure the TPM device using chardev backend\\n\",\n>       QEMU_ARCH_ALL)\n>   STEXI\n>\n> @@ -3130,8 +3132,8 @@ The general form of a TPM device option is:\n>\n>   @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]\n>   @findex -tpmdev\n> -Backend type must be:\n> -@option{passthrough}.\n> +Backend type must be either one of the following:\n> +@option{passthrough}, @option{emulator}.\n>\n>   The specific backend type will determine the applicable options.\n>   The @code{-tpmdev} option creates the TPM backend and requires a\n> @@ -3181,6 +3183,20 @@ To create a passthrough TPM use the following two options:\n>   Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by\n>   @code{tpmdev=tpm0} in the device option.\n>\n> +@item -tpmdev emulator, id=@var{id}, chardev=@var{dev}\n> +\n> +(Linux-host only) Enable access to a TPM emulator using Unix domain socket based\n> +chardev backend.\n> +\n> +@option{chardev} specifies the unique ID of a character device backend that provides connection to the software TPM server.\n> +\n> +To create a TPM emulator backend device with chardev socket backend:\n> +@example\n> +\n> +-chardev socket,id=chrtpm,path=/tmp/swtpm-ctrl -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0\n> +\n> +@end example\n> +\n>   @end table\n>\n>   ETEXI\n\n\n\n     Stefan","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":"ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xzJj91MkZz9s7g\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 23 Sep 2017 02:24:45 +1000 (AEST)","from localhost ([::1]:59968 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dvQkt-0000qd-8J\n\tfor incoming@patchwork.ozlabs.org; Fri, 22 Sep 2017 12:24:43 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:35222)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <stefanb@linux.vnet.ibm.com>) id 1dvQk2-0000lZ-Gs\n\tfor qemu-devel@nongnu.org; Fri, 22 Sep 2017 12:23:54 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <stefanb@linux.vnet.ibm.com>) id 1dvQjy-0001Dp-9s\n\tfor qemu-devel@nongnu.org; Fri, 22 Sep 2017 12:23:50 -0400","from mx0b-001b2d01.pphosted.com ([148.163.158.5]:44667\n\thelo=mx0a-001b2d01.pphosted.com)\n\tby eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <stefanb@linux.vnet.ibm.com>)\n\tid 1dvQjy-0001DX-1N\n\tfor qemu-devel@nongnu.org; Fri, 22 Sep 2017 12:23:46 -0400","from pps.filterd (m0098416.ppops.net [127.0.0.1])\n\tby mx0b-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv8MGJeVA101919\n\tfor <qemu-devel@nongnu.org>; Fri, 22 Sep 2017 12:23:43 -0400","from e35.co.us.ibm.com (e35.co.us.ibm.com [32.97.110.153])\n\tby mx0b-001b2d01.pphosted.com with ESMTP id 2d55tqrfsq-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <qemu-devel@nongnu.org>; Fri, 22 Sep 2017 12:23:42 -0400","from localhost\n\tby e35.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <qemu-devel@nongnu.org> from <stefanb@linux.vnet.ibm.com>;\n\tFri, 22 Sep 2017 10:23:41 -0600","from b03cxnp07029.gho.boulder.ibm.com (9.17.130.16)\n\tby e35.co.us.ibm.com (192.168.1.135) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tFri, 22 Sep 2017 10:23:38 -0600","from b03ledav005.gho.boulder.ibm.com\n\t(b03ledav005.gho.boulder.ibm.com [9.17.130.236])\n\tby b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with\n\tESMTP id v8MGNc8d8978740; Fri, 22 Sep 2017 09:23:38 -0700","from b03ledav005.gho.boulder.ibm.com (unknown [127.0.0.1])\n\tby IMSVA (Postfix) with ESMTP id 39363BE047;\n\tFri, 22 Sep 2017 10:23:38 -0600 (MDT)","from sbct-3.pok.ibm.com (unknown [9.47.158.153])\n\tby b03ledav005.gho.boulder.ibm.com (Postfix) with ESMTP id A07B4BE03A;\n\tFri, 22 Sep 2017 10:23:37 -0600 (MDT)"],"To":"Amarnath Valluri <amarnath.valluri@intel.com>, qemu-devel@nongnu.org","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>","From":"Stefan Berger <stefanb@linux.vnet.ibm.com>","Date":"Fri, 22 Sep 2017 12:23:37 -0400","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101\n\tThunderbird/45.4.0","MIME-Version":"1.0","In-Reply-To":"<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>","Content-Type":"text/plain; charset=windows-1252; format=flowed","Content-Transfer-Encoding":"7bit","X-TM-AS-GCONF":"00","x-cbid":"17092216-0012-0000-0000-0000150BA1C6","X-IBM-SpamModules-Scores":"","X-IBM-SpamModules-Versions":"BY=3.00007778; HX=3.00000241; KW=3.00000007;\n\tPH=3.00000004; SC=3.00000231; SDB=6.00920782; UDB=6.00462708;\n\tIPR=6.00701003; \n\tBA=6.00005601; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009;\n\tZB=6.00000000; \n\tZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00017249;\n\tXFM=3.00000015; UTC=2017-09-22 16:23:40","X-IBM-AV-DETECTION":"SAVI=unused REMOTE=unused XFE=unused","x-cbparentid":"17092216-0013-0000-0000-00004F97F52E","Message-Id":"<36625c01-a29e-907c-1662-e1ff01e59a43@linux.vnet.ibm.com>","X-Proofpoint-Virus-Version":"vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-09-22_06:, , signatures=0","X-Proofpoint-Spam-Details":"rule=outbound_notspam policy=outbound score=0\n\tspamscore=0 suspectscore=2\n\tmalwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam\n\tadjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000\n\tdefinitions=main-1709220231","X-detected-operating-system":"by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy]","X-Received-From":"148.163.158.5","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@gmail.com>,\n\t\"Dr. David Alan Gilbert\" <dgilbert@redhat.com>, \n\tMarkus Armbruster <armbru@redhat.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}},{"id":1774275,"web_url":"http://patchwork.ozlabs.org/comment/1774275/","msgid":"<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>","list_archive_url":null,"date":"2017-09-24T18:52:40","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":6442,"url":"http://patchwork.ozlabs.org/api/people/6442/","name":"Marc-André Lureau","email":"marcandre.lureau@gmail.com"},"content":"Hi\n\nThanks for the nice update, removing the exec() code, using chardev\nand a private socketpair. Some comments below:\n\nOn Fri, Sep 22, 2017 at 2:33 PM, Amarnath Valluri\n<amarnath.valluri@intel.com> wrote:\n> This change introduces a new TPM backend driver that can communicate with\n> swtpm(software TPM emulator) using unix domain socket interface. QEMU talks to\n> TPM emulator using socket based chardev backend device.\n>\n> Swtpm uses two Unix sockets for communications, one for plain TPM commands and\n> responses, and one for out-of-band control messages. QEMU passes data socket\n> been used over the control channel.\n>\n> The swtpm and associated tools can be found here:\n>     https://github.com/stefanberger/swtpm\n>\n> The swtpm's control channel protocol specification can be found here:\n>     https://github.com/stefanberger/swtpm/wiki/Control-Channel-Specification\n>\n> Usage:\n>     # setup TPM state directory\n>     mkdir /tmp/mytpm\n>     chown -R tss:root /tmp/mytpm\n>     /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek\n>\n>     # Ask qemu to use TPM emulator with given tpm state directory\n>     qemu-system-x86_64 \\\n>         [...] \\\n>         -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \\\n>         -tpmdev emulator,id=tpm0,chardev=chrtpm \\\n>         -device tpm-tis,tpmdev=tpm0 \\\n>         [...]\n>\n> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>\n> ---\n>  configure             |  15 +-\n>  hmp.c                 |   5 +\n>  hw/tpm/Makefile.objs  |   1 +\n>  hw/tpm/tpm_emulator.c | 649 ++++++++++++++++++++++++++++++++++++++++++++++++++\n>  hw/tpm/tpm_ioctl.h    | 246 +++++++++++++++++++\n>  qapi/tpm.json         |  21 +-\n>  qemu-options.hx       |  22 +-\n>  7 files changed, 950 insertions(+), 9 deletions(-)\n>  create mode 100644 hw/tpm/tpm_emulator.c\n>  create mode 100644 hw/tpm/tpm_ioctl.h\n>\n> diff --git a/configure b/configure\n> index cb0f7ed..ce2df2d 100755\n> --- a/configure\n> +++ b/configure\n> @@ -3461,10 +3461,15 @@ fi\n>  ##########################################\n>  # TPM passthrough is only on x86 Linux\n>\n> -if test \"$targetos\" = Linux && test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\n> -  tpm_passthrough=$tpm\n> +if test \"$targetos\" = Linux; then\n> +  tpm_emulator=$tpm\n> +  if test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\n> +    tpm_passthrough=$tpm\n> +  else\n> +    tpm_passthrough=no\n> +  fi\n>  else\n> -  tpm_passthrough=no\n> +  tpm_emulator=no\n>  fi\n>\n>  ##########################################\n> @@ -5359,6 +5364,7 @@ echo \"gcov enabled      $gcov\"\n>  echo \"TPM support       $tpm\"\n>  echo \"libssh2 support   $libssh2\"\n>  echo \"TPM passthrough   $tpm_passthrough\"\n> +echo \"TPM emulator      $tpm_emulator\"\n>  echo \"QOM debugging     $qom_cast_debug\"\n>  echo \"Live block migration $live_block_migration\"\n>  echo \"lzo support       $lzo\"\n> @@ -5943,6 +5949,9 @@ if test \"$tpm\" = \"yes\"; then\n>    if test \"$tpm_passthrough\" = \"yes\"; then\n>      echo \"CONFIG_TPM_PASSTHROUGH=y\" >> $config_host_mak\n>    fi\n> +  if test \"$tpm_emulator\" = \"yes\"; then\n> +    echo \"CONFIG_TPM_EMULATOR=y\" >> $config_host_mak\n\nIt shouldn't require Linux, but posix (and I assume a port to other\nsystems isn't impossible). same for build-sys / help / comments.\n\n> +  fi\n>  fi\n>\n>  echo \"TRACE_BACKENDS=$trace_backends\" >> $config_host_mak\n> diff --git a/hmp.c b/hmp.c\n> index cf62b2e..7e69eca 100644\n> --- a/hmp.c\n> +++ b/hmp.c\n> @@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)\n>      Error *err = NULL;\n>      unsigned int c = 0;\n>      TPMPassthroughOptions *tpo;\n> +    TPMEmulatorOptions *teo;\n>\n>      info_list = qmp_query_tpm(&err);\n>      if (err) {\n> @@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)\n>                             tpo->has_cancel_path ? \",cancel-path=\" : \"\",\n>                             tpo->has_cancel_path ? tpo->cancel_path : \"\");\n>              break;\n> +        case TPM_TYPE_EMULATOR:\n> +            teo = ti->options->u.emulator.data;\n> +            monitor_printf(mon, \",chardev=%s\", teo->chardev);\n> +            break;\n>          case TPM_TYPE__MAX:\n>              break;\n>          }\n> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs\n> index 64cecc3..41f0b7a 100644\n> --- a/hw/tpm/Makefile.objs\n> +++ b/hw/tpm/Makefile.objs\n> @@ -1,2 +1,3 @@\n>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o\n>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o\n> +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o\n> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c\n> new file mode 100644\n> index 0000000..c02bbe2\n> --- /dev/null\n> +++ b/hw/tpm/tpm_emulator.c\n> @@ -0,0 +1,649 @@\n> +/*\n> + *  emulator TPM driver\n> + *\n> + *  Copyright (c) 2017 Intel Corporation\n> + *  Author: Amarnath Valluri <amarnath.valluri@intel.com>\n> + *\n> + *  Copyright (c) 2010 - 2013 IBM Corporation\n> + *  Authors:\n> + *    Stefan Berger <stefanb@us.ibm.com>\n> + *\n> + *  Copyright (C) 2011 IAIK, Graz University of Technology\n> + *    Author: Andreas Niederl\n> + *\n> + * This library is free software; you can redistribute it and/or\n> + * modify it under the terms of the GNU Lesser General Public\n> + * License as published by the Free Software Foundation; either\n> + * version 2 of the License, or (at your option) any later version.\n> + *\n> + * This library is distributed in the hope that it will be useful,\n> + * but WITHOUT ANY WARRANTY; without even the implied warranty of\n> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n> + * Lesser General Public License for more details.\n> + *\n> + * You should have received a copy of the GNU Lesser General Public\n> + * License along with this library; if not, see <http://www.gnu.org/licenses/>\n> + *\n> + */\n> +\n> +#include \"qemu/osdep.h\"\n> +#include \"qemu/error-report.h\"\n> +#include \"qemu/sockets.h\"\n> +#include \"io/channel-socket.h\"\n> +#include \"sysemu/tpm_backend.h\"\n> +#include \"tpm_int.h\"\n> +#include \"hw/hw.h\"\n> +#include \"hw/i386/pc.h\"\n> +#include \"tpm_util.h\"\n> +#include \"tpm_ioctl.h\"\n> +#include \"migration/blocker.h\"\n> +#include \"qapi/error.h\"\n> +#include \"chardev/char-fe.h\"\n> +\n> +#include <fcntl.h>\n> +#include <sys/types.h>\n> +#include <sys/stat.h>\n> +#include <stdio.h>\n> +\n> +#define DEBUG_TPM 0\n> +\n> +#define DPRINT(fmt, ...) do { \\\n> +    if (DEBUG_TPM) { \\\n> +        fprintf(stderr, fmt, ## __VA_ARGS__); \\\n> +    } \\\n> +} while (0);\n> +\n> +#define DPRINTF(fmt, ...) DPRINT(\"tpm-emulator: \"fmt\"\\n\", __VA_ARGS__)\n\nI would define a single DPRINTF() (& drop DPRINT usage below)\n\n\n> +\n> +#define TYPE_TPM_EMULATOR \"tpm-emulator\"\n> +#define TPM_EMULATOR(obj) \\\n> +    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)\n> +\n> +#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))\n> +\n> +static const TPMDriverOps tpm_emulator_driver;\n> +\n> +/* data structures */\n> +typedef struct TPMEmulator {\n> +    TPMBackend parent;\n> +\n> +    TPMEmulatorOptions *options;\n\nContrary to my comment on previous patch, I realize it is convenient\nto have a qapi pointer here, so you can use the free visitor later.\n\n> +    CharBackend ctrl_dev;\n\nctrl_chr perhaps? or just chr or be (the most common name in other devices).\n\n> +    QIOChannel *data_ioc;\n> +    bool op_executing;\n> +    bool op_canceled;\n\nI think those 2 fields can be dropped, see below.\n\n> +    bool had_startup_error;\n\nI think some little refactoring could remove the whole\nhad_startup_error() backend & callback before or after the series.\ntpm_backend_startup_tpm() already returns an error code.  device or\ncommon backend code could handle & remember that.\n\n> +    TPMVersion tpm_version;\n\nThis is probably worth to consider in common code instead, but let's\nnot worry about it.\n\n> +    ptm_cap caps; /* capabilities of the TPM */\n> +    uint8_t cur_locty_number; /* last set locality */\n> +    QemuMutex state_lock;\n> +    Error *migration_blocker;\n> +} TPMEmulator;\n> +\n> +\n> +static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long cmd, void *msg,\n> +                                size_t msg_len_in, size_t msg_len_out)\n> +{\n> +    uint32_t cmd_no = cpu_to_be32(cmd);\n> +    ssize_t n = sizeof(uint32_t) + msg_len_in;\n> +    uint8_t *buf = NULL;\n> +\n> +    buf = (uint8_t *)malloc(n);\n\ncould be g_alloca() instead. Alternatively, why not call 2 write() instead?\n\nnone of the casts in this function are necessary, please remove them.\n\n> +    memcpy(buf, &cmd_no, sizeof(cmd_no));\n> +    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);\n> +\n> +    n += qemu_chr_fe_write_all(dev, (const uint8_t *)buf, n);\n\nweird\n\n> +    free(buf);\n> +\n> +    if (n > 0) {\n\nwith the n += above, you'll get interesting behaviour :)\n\nYou probably want to check if any write above failed, and return early\nfor the error case.\n\nPlease improve the error handling in this function\n\n> +        if (msg_len_out > 0) {\n> +            n = qemu_chr_fe_read_all(dev, (uint8_t *)msg, msg_len_out);\n> +            /* simulate ioctl return value */\n> +            if (n > 0) {\n> +                n = 0;\n> +            }\n> +        } else {\n> +            n = 0;\n> +        }\n> +    }\n> +    return n;\n> +}\n> +\n> +static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,\n\ntpm_pt was tpm_passthrough I suppose.\n\nPlease rename tpm_pt tpm_emu (or I would suggest \"self\", but this\nisn't common name in qemu code - it's actually common in a close\nc-object world., and it is quite convenient...)\n\n> +                                     const uint8_t *in, uint32_t in_len,\n> +                                     uint8_t *out, uint32_t out_len,\n> +                                     bool *selftest_done)\n> +{\n> +    ssize_t ret;\n> +    bool is_selftest = false;\n> +    const struct tpm_resp_hdr *hdr = NULL;\n> +    Error *err = NULL;\n> +\n> +    tpm_pt->op_canceled = false;\n> +    tpm_pt->op_executing = true;\n> +    if (selftest_done) {\n> +        *selftest_done = false;\n> +        is_selftest = tpm_util_is_selftest(in, in_len);\n> +    }\n> +\n> +    ret = qio_channel_write(tpm_pt->data_ioc, (char *)in, in_len, &err);\n\nhmm, too bad qio_channel_write() doesn't take a void *\n\nwhy not write_all()?\n\n> +    if (ret != in_len || err) {\n> +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n\nI don't think ECANCELED make sense for emulator code.\n\n> +            error_report(\"tpm-emulator: error while transmitting data \"\n> +                         \"to TPM: %s\", err ? error_get_pretty(err) : \"\");\n> +            error_free(err);\n> +        }\n> +        goto err_exit;\n> +    }\n> +\n> +    tpm_pt->op_executing = false;\n> +\n> +    ret = qio_channel_read(tpm_pt->data_ioc, (char *)out, out_len, &err);\n> +    if (ret < 0 || err) {\n\nread_all() ?\n\n> +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n> +            error_report(\"tpm-emulator: error while reading data from \"\n> +                         \"TPM: %s\", err ? error_get_pretty(err) : \"\");\n> +            error_free(err);\n> +        }\n> +    } else if (ret >= sizeof(*hdr)) {\n> +        hdr = (struct tpm_resp_hdr *)out;\n> +    }\n> +\n> +    if (!hdr || be32_to_cpu(hdr->len) != ret) {\n> +        error_report(\"tpm-emulator: received invalid response \"\n> +                     \"packet from TPM with length :%ld\", ret);\n> +        ret = -1;\n> +        goto err_exit;\n> +    }\n> +\n> +    if (is_selftest) {\n> +        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);\n> +    }\n> +\n> +    return 0;\n> +\n> +err_exit:\n> +    if (ret < 0) {\n> +        tpm_util_write_fatal_error_response(out, out_len);\n> +    }\n> +\n> +    tpm_pt->op_executing = false;\n> +\n> +    return ret;\n> +}\n> +\n> +static int tpm_emulator_set_locality(TPMEmulator *tpm_pt, uint8_t locty_number)\n> +{\n> +    ptm_loc loc;\n> +\n> +    DPRINTF(\"%s : locality: 0x%x\", __func__, locty_number);\n> +\n> +    if (tpm_pt->cur_locty_number != locty_number) {\n\nreturn early instead if ==, to avoid code indent etc\n\n> +        DPRINTF(\"setting locality : 0x%x\", locty_number);\n> +        loc.u.req.loc = locty_number;\n\nThis number isn't set in be like the rest of the protocol?\n\n> +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_LOCALITY, &loc,\n> +                             sizeof(loc), sizeof(loc)) < 0) {\n> +            error_report(\"tpm-emulator: could not set locality : %s\",\n> +                         strerror(errno));\n> +            return -1;\n> +        }\n> +        loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);\n> +        if (loc.u.resp.tpm_result != 0) {\n> +            error_report(\"tpm-emulator: TPM result for set locality : 0x%x\",\n> +                         loc.u.resp.tpm_result);\n> +            return -1;\n> +        }\n> +        tpm_pt->cur_locty_number = locty_number;\n> +    }\n> +    return 0;\n> +}\n> +\n> +static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    TPMLocality *locty = NULL;\n> +    bool selftest_done = false;\n> +\n> +    DPRINTF(\"processing command type %d\", cmd);\n> +\n> +    switch (cmd) {\n> +    case TPM_BACKEND_CMD_PROCESS_CMD:\n> +        qemu_mutex_lock(&tpm_pt->state_lock);\n> +        locty = tb->tpm_state->locty_data;\n> +        if (tpm_emulator_set_locality(tpm_pt,\n> +                                      tb->tpm_state->locty_number) < 0) {\n> +            tpm_util_write_fatal_error_response(locty->r_buffer.buffer,\n> +                                           locty->r_buffer.size);\n\nreturn / goto here instead of else.\n\n> +        } else {\n> +            tpm_emulator_unix_tx_bufs(tpm_pt, locty->w_buffer.buffer,\n> +                                              locty->w_offset,\n> +                                              locty->r_buffer.buffer,\n> +                                              locty->r_buffer.size,\n> +                                              &selftest_done);\n\nno error handling?\n\n> +        }\n> +\n> +        tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,\n> +                               selftest_done);\n> +        qemu_mutex_unlock(&tpm_pt->state_lock);\n> +\n> +        break;\n> +    case TPM_BACKEND_CMD_INIT:\n> +    case TPM_BACKEND_CMD_END:\n> +    case TPM_BACKEND_CMD_TPM_RESET:\n> +        /* nothing to do */\n> +        break;\n> +    }\n> +}\n> +\n> +/*\n> + * Gracefully shut down the external unixio TPM\n> + */\n> +static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)\n> +{\n> +    ptm_res res;\n> +\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SHUTDOWN, &res, 0,\n> +                         sizeof(res)) < 0) {\n> +        error_report(\"tpm-emulator: Could not cleanly shutdown the TPM: %s\",\n> +                     strerror(errno));\n> +    } else if (res != 0) {\n> +        error_report(\"tpm-emulator: TPM result for sutdown: 0x%x\",\n> +                     be32_to_cpu(res));\n> +    }\n> +}\n> +\n> +static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)\n> +{\n> +    DPRINTF(\"%s\", __func__);\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_GET_CAPABILITY,\n> +                         &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) < 0) {\n> +        error_report(\"tpm-emulator: probing failed : %s\", strerror(errno));\n> +        return -1;\n> +    }\n> +\n> +    tpm_pt->caps = be64_to_cpu(tpm_pt->caps);\n> +\n> +    DPRINTF(\"capbilities : 0x%lx\", tpm_pt->caps);\n> +\n> +    return 0;\n> +}\n> +\n> +static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)\n> +{\n> +    ptm_cap caps = 0;\n> +    const char *tpm = NULL;\n> +\n> +    /* check for min. required capabilities */\n> +    switch (tpm_pt->tpm_version) {\n> +    case TPM_VERSION_1_2:\n> +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |\n> +               PTM_CAP_SET_LOCALITY;\n> +        tpm = \"1.2\";\n> +        break;\n> +    case TPM_VERSION_2_0:\n> +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |\n> +               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED;\n> +        tpm = \"2\";\n> +        break;\n> +    case TPM_VERSION_UNSPEC:\n> +        error_report(\"tpm-emulator: TPM version has not been set\");\n> +        return -1;\n> +    }\n> +\n> +    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {\n> +        error_report(\"tpm-emulator: TPM does not implement minimum set of \"\n> +                     \"required capabilities for TPM %s (0x%x)\", tpm, (int)caps);\n> +        return -1;\n> +    }\n> +\n> +    return 0;\n> +}\n> +\n> +static int tpm_emulator_startup_tpm(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_init init;\n> +    ptm_res res;\n> +\n> +    DPRINTF(\"%s\", __func__);\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_INIT, &init, sizeof(init),\n> +                         sizeof(init)) < 0) {\n> +        error_report(\"tpm-emulator: could not send INIT: %s\",\n> +                     strerror(errno));\n> +        goto err_exit;\n> +    }\n> +\n> +    res = be32_to_cpu(init.u.resp.tpm_result);\n> +    if (res) {\n> +        error_report(\"tpm-emulator: TPM result for CMD_INIT: 0x%x\", res);\n> +        goto err_exit;\n> +    }\n> +    return 0;\n> +\n> +err_exit:\n> +    tpm_pt->had_startup_error = true;\n> +    return -1;\n> +}\n> +\n> +static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_est est;\n> +\n> +    DPRINTF(\"%s\", __func__);\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_GET_TPMESTABLISHED, &est, 0,\n> +                         sizeof(est)) < 0) {\n> +        error_report(\"tpm-emulator: Could not get the TPM established flag: %s\",\n> +                     strerror(errno));\n> +        return false;\n> +    }\n> +    DPRINTF(\"established flag: %0x\", est.u.resp.bit);\n> +\n> +    return (est.u.resp.bit != 0);\n> +}\n> +\n> +static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,\n> +                                                   uint8_t locty)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_reset_est reset_est;\n> +    ptm_res res;\n> +\n> +    /* only a TPM 2.0 will support this */\n> +    if (tpm_pt->tpm_version == TPM_VERSION_2_0) {\n> +        reset_est.u.req.loc = tpm_pt->cur_locty_number;\n> +\n> +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_RESET_TPMESTABLISHED,\n> +                                 &reset_est, sizeof(reset_est),\n> +                                 sizeof(reset_est)) < 0) {\n> +            error_report(\"tpm-emulator: Could not reset the establishment bit: \"\n> +                          \"%s\", strerror(errno));\n> +            return -1;\n> +        }\n> +\n> +        res = be32_to_cpu(reset_est.u.resp.tpm_result);\n> +        if (res) {\n> +            error_report(\"tpm-emulator: TPM result for rest establixhed flag: \"\n> +                         \"0x%x\", res);\n> +            return -1;\n> +        }\n> +    }\n> +\n> +    return 0;\n> +}\n> +\n> +static bool tpm_emulator_had_startup_error(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +\n> +    return tpm_pt->had_startup_error;\n> +}\n> +\n> +static void tpm_emulator_cancel_cmd(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    ptm_res res;\n> +\n> +    /*\n> +     * As of Linux 3.7 the tpm_tis driver does not properly cancel\n> +     * commands on all TPM manufacturers' TPMs.\n> +     * Only cancel if we're busy so we don't cancel someone else's\n> +     * command, e.g., a command executed on the host.\n> +     */\n> +    if (tpm_pt->op_executing) {\n\nThe field is set in the worker thread. This is racy. Fortunately this\nis not relevant for emulator, I think you can simply drop that check\nand the variable. Stefan should confirm though.\n\n> +        if (TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, PTM_CAP_CANCEL_TPM_CMD)) {\n> +            if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_CANCEL_TPM_CMD,\n> +                                     &res, 0, sizeof(res)) < 0) {\n> +                error_report(\"tpm-emulator: Could not cancel command: %s\",\n> +                             strerror(errno));\n> +            } else if (res != 0) {\n> +                error_report(\"tpm-emulator: Failed to cancel TPM: 0x%x\",\n> +                             be32_to_cpu(res));\n> +            } else {\n> +                tpm_pt->op_canceled = true;\n> +            }\n> +        }\n> +    }\n> +}\n> +\n> +static void tpm_emulator_reset(TPMBackend *tb)\n> +{\n> +    DPRINTF(\"%s\", __func__);\n> +\n> +    tpm_emulator_cancel_cmd(tb);\n> +}\n> +\n> +static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +\n> +    return tpm_pt->tpm_version;\n> +}\n> +\n> +static void tpm_emulator_block_migration(TPMEmulator *tpm_pt)\n> +{\n> +    Error *err = NULL;\n> +\n> +    error_setg(&tpm_pt->migration_blocker,\n> +               \"Migration disabled: TPM emulator not yet migratable\");\n> +    migrate_add_blocker(tpm_pt->migration_blocker, &err);\n> +    if (err) {\n> +        error_free(err);\n\nprobably better to report_err it instead\n\n> +        error_free(tpm_pt->migration_blocker);\n> +        tpm_pt->migration_blocker = NULL;\n\nand return an error code.\n\n> +    }\n> +}\n> +\n> +static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_pt)\n> +{\n> +    ptm_res res;\n> +    Error *err = NULL;\n> +    int fds[2] = { -1, -1 };\n> +\n> +    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {\n> +        error_report(\"tpm-emulator: Failed to create socketpair\");\n> +        return -1;\n> +    }\n> +\n> +    qemu_chr_fe_set_msgfds(&tpm_pt->ctrl_dev, fds + 1, 1);\n> +\n> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_DATAFD, &res, 0,\n> +                    sizeof(res)) || res != 0) {\n\nYay! for making life easier and hiding a protocol detail.\n\n> +        error_report(\"tpm-emulator: Failed to send CMD_SET_DATAFD: %s\",\n> +                     strerror(errno));\n> +        goto err_exit;\n> +    }\n> +\n> +    tpm_pt->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));\n> +    if (err) {\n> +        error_report(\"tpm-emulator: Failed to create io channel : %s\",\n> +                       error_get_pretty(err));\n\nerror_prepend()?\n\n> +        error_free(err);\n> +        goto err_exit;\n> +    }\n\nclose fds[1] ?\n\n> +\n> +    return 0;\n> +\n> +err_exit:\n> +    closesocket(fds[0]);\n> +    closesocket(fds[1]);\n> +    return -1;\n> +}\n> +\n> +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt, QemuOpts *opts)\n> +{\n> +    const char *value;\n> +\n> +    value = qemu_opt_get(opts, \"chardev\");\n> +    if (value) {\n> +        Error *err = NULL;\n> +        Chardev *dev = qemu_chr_find(value);\n> +\n> +        tpm_pt->options->chardev = g_strdup(value);\n> +\n> +        if (!dev || !qemu_chr_fe_init(&tpm_pt->ctrl_dev, dev, &err)) {\n> +            error_report(\"tpm-emulator: No valid chardev found at '%s': %s\",\n> +                         value, err ? error_get_pretty(err) : \"\");\n> +            error_free(err);\n\nerror_prepend\n\n> +            goto err;\n> +        }\n> +    }\n> +\n> +    if (tpm_emulator_prepare_data_fd(tpm_pt) < 0) {\n> +        goto err;\n> +    }\n> +\n> +    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used\n> +     * by passthrough driver, which not yet using GIOChannel.\n> +     */\n> +    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_pt->data_ioc)->fd,\n> +                             &tpm_pt->tpm_version)) {\n> +        error_report(\"'%s' is not emulating TPM device. Error: %s\",\n> +                      tpm_pt->options->chardev, strerror(errno));\n> +        goto err;\n> +    }\n> +\n> +    DPRINTF(\"TPM Version %s\", tpm_pt->tpm_version == TPM_VERSION_1_2 ? \"1.2\" :\n> +             (tpm_pt->tpm_version == TPM_VERSION_2_0 ?  \"2.0\" : \"Unspecified\"));\n> +\n> +    if (tpm_emulator_probe_caps(tpm_pt) ||\n> +        tpm_emulator_check_caps(tpm_pt)) {\n> +        goto err;\n> +    }\n> +\n> +    tpm_emulator_block_migration(tpm_pt);\n> +\n> +    return 0;\n> +\n> +err:\n> +    DPRINT(\"Startup error\\n\");\n> +    return -1;\n> +}\n> +\n> +static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)\n> +{\n> +    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));\n> +\n> +    tb->id = g_strdup(id);\n> +\n> +    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {\n> +        goto err_exit;\n> +    }\n> +\n> +    return tb;\n> +\n> +err_exit:\n> +    object_unref(OBJECT(tb));\n> +\n> +    return NULL;\n> +}\n> +\n> +static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n> +    TpmTypeOptions *options = NULL;\n> +    TPMEmulatorOptions *eoptions = NULL;\n> +\n> +    eoptions = g_new0(TPMEmulatorOptions, 1);\n> +    if (!eoptions) {\n> +        return NULL;\n> +    }\n> +    DPRINTF(\"%s\", __func__);\n> +\n> +    eoptions->chardev = g_strdup(tpm_pt->options->chardev);\n> +    options = g_new0(TpmTypeOptions, 1);\n> +    if (!options) {\n> +        qapi_free_TPMEmulatorOptions(eoptions);\n> +        return NULL;\n> +    }\n> +\n> +    options->type = TPM_TYPE_EMULATOR;\n> +    options->u.emulator.data = eoptions;\n\nI think this is a job for QAPI_CLONE.\n\n> +\n> +    return options;\n> +}\n> +\n> +static const QemuOptDesc tpm_emulator_cmdline_opts[] = {\n> +    TPM_STANDARD_CMDLINE_OPTS,\n> +    {\n> +        .name = \"chardev\",\n> +        .type = QEMU_OPT_STRING,\n> +        .help = \"Character device to use for out-of-band control messages\",\n> +    },\n> +    { /* end of list */ },\n> +};\n> +\n> +static const TPMDriverOps tpm_emulator_driver = {\n> +    .type                     = TPM_TYPE_EMULATOR,\n> +    .opts                     = tpm_emulator_cmdline_opts,\n> +    .desc                     = \"TPM emulator backend driver\",\n> +\n> +    .create                   = tpm_emulator_create,\n> +    .startup_tpm              = tpm_emulator_startup_tpm,\n> +    .reset                    = tpm_emulator_reset,\n> +    .had_startup_error        = tpm_emulator_had_startup_error,\n> +    .cancel_cmd               = tpm_emulator_cancel_cmd,\n> +    .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,\n> +    .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,\n> +    .get_tpm_version          = tpm_emulator_get_tpm_version,\n> +    .get_tpm_options          = tpm_emulator_get_tpm_options,\n> +};\n> +\n> +static void tpm_emulator_inst_init(Object *obj)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n> +\n> +    DPRINTF(\"%s\", __func__);\n> +    tpm_pt->options = g_new0(TPMEmulatorOptions, 1);\n> +    tpm_pt->op_executing = tpm_pt->op_canceled = false;\n> +    tpm_pt->had_startup_error = false;\n> +    tpm_pt->cur_locty_number = ~0;\n> +    qemu_mutex_init(&tpm_pt->state_lock);\n> +}\n> +\n> +static void tpm_emulator_inst_finalize(Object *obj)\n> +{\n> +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n> +\n> +    tpm_emulator_cancel_cmd(TPM_BACKEND(obj));\n> +    tpm_emulator_shutdown(tpm_pt);\n> +\n> +    if (tpm_pt->data_ioc) {\n> +        qio_channel_close(tpm_pt->data_ioc, NULL);\n> +    }\n> +\n> +    qemu_chr_fe_deinit(&tpm_pt->ctrl_dev, false);\n> +\n> +    if (tpm_pt->options) {\n> +        qapi_free_TPMEmulatorOptions(tpm_pt->options);\n> +    }\n> +\n> +    if (tpm_pt->migration_blocker) {\n> +        migrate_del_blocker(tpm_pt->migration_blocker);\n> +        error_free(tpm_pt->migration_blocker);\n> +    }\n> +}\n> +\n> +static void tpm_emulator_class_init(ObjectClass *klass, void *data)\n> +{\n> +    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);\n> +    tbc->ops = &tpm_emulator_driver;\n> +    tbc->handle_request = tpm_emulator_handle_request;\n> +}\n> +\n> +static const TypeInfo tpm_emulator_info = {\n> +    .name = TYPE_TPM_EMULATOR,\n> +    .parent = TYPE_TPM_BACKEND,\n> +    .instance_size = sizeof(TPMEmulator),\n> +    .class_init = tpm_emulator_class_init,\n> +    .instance_init = tpm_emulator_inst_init,\n> +    .instance_finalize = tpm_emulator_inst_finalize,\n> +};\n> +\n> +static void tpm_emulator_register(void)\n> +{\n> +    type_register_static(&tpm_emulator_info);\n> +    tpm_register_driver(&tpm_emulator_driver);\n> +}\n> +\n> +type_init(tpm_emulator_register)\n> diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h\n> new file mode 100644\n> index 0000000..33564b1\n> --- /dev/null\n> +++ b/hw/tpm/tpm_ioctl.h\n\nThis file is copied from swtpm project. Could swtpm have it installed\non system instead?\n\n> @@ -0,0 +1,246 @@\n> +/*\n> + * tpm_ioctl.h\n> + *\n> + * (c) Copyright IBM Corporation 2014, 2015.\n> + *\n> + * This file is licensed under the terms of the 3-clause BSD license\n> + */\n> +#ifndef _TPM_IOCTL_H_\n> +#define _TPM_IOCTL_H_\n> +\n> +#include <stdint.h>\n> +#include <sys/uio.h>\n> +#include <sys/types.h>\n> +#include <sys/ioctl.h>\n> +\n> +/*\n> + * Every response from a command involving a TPM command execution must hold\n> + * the ptm_res as the first element.\n> + * ptm_res corresponds to the error code of a command executed by the TPM.\n> + */\n> +\n> +typedef uint32_t ptm_res;\n> +\n> +/* PTM_GET_TPMESTABLISHED: get the establishment bit */\n> +struct ptm_est {\n> +    union {\n> +        struct {\n> +            ptm_res tpm_result;\n> +            unsigned char bit; /* TPM established bit */\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* PTM_RESET_TPMESTABLISHED: reset establishment bit */\n> +struct ptm_reset_est {\n> +    union {\n> +        struct {\n> +            uint8_t loc; /* locality to use */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* PTM_INIT */\n> +struct ptm_init {\n> +    union {\n> +        struct {\n> +            uint32_t init_flags; /* see definitions below */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* above init_flags */\n> +#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)\n> +    /* delete volatile state file after reading it */\n> +\n> +/* PTM_SET_LOCALITY */\n> +struct ptm_loc {\n> +    union {\n> +        struct {\n> +            uint8_t loc; /* locality to set */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* PTM_HASH_DATA: hash given data */\n> +struct ptm_hdata {\n> +    union {\n> +        struct {\n> +            uint32_t length;\n> +            uint8_t data[4096];\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/*\n> + * size of the TPM state blob to transfer; x86_64 can handle 8k,\n> + * ppc64le only ~7k; keep the response below a 4k page size\n> + */\n> +#define PTM_STATE_BLOB_SIZE (3 * 1024)\n> +\n> +/*\n> + * The following is the data structure to get state blobs from the TPM.\n> + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads\n> + * with this ioctl and with adjusted offset are necessary. All bytes\n> + * must be transferred and the transfer is done once the last byte has been\n> + * returned.\n> + * It is possible to use the read() interface for reading the data; however, the\n> + * first bytes of the state blob will be part of the response to the ioctl(); a\n> + * subsequent read() is only necessary if the total length (totlength) exceeds\n> + * the number of received bytes. seek() is not supported.\n> + */\n> +struct ptm_getstate {\n> +    union {\n> +        struct {\n> +            uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */\n> +            uint32_t type;        /* which blob to pull */\n> +            uint32_t offset;      /* offset from where to read */\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +            uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */\n> +            uint32_t totlength;   /* total length that will be transferred */\n> +            uint32_t length;      /* number of bytes in following buffer */\n> +            uint8_t  data[PTM_STATE_BLOB_SIZE];\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/* TPM state blob types */\n> +#define PTM_BLOB_TYPE_PERMANENT  1\n> +#define PTM_BLOB_TYPE_VOLATILE   2\n> +#define PTM_BLOB_TYPE_SAVESTATE  3\n> +\n> +/* state_flags above : */\n> +#define PTM_STATE_FLAG_DECRYPTED     1 /* on input:  get decrypted state */\n> +#define PTM_STATE_FLAG_ENCRYPTED     2 /* on output: state is encrypted */\n> +\n> +/*\n> + * The following is the data structure to set state blobs in the TPM.\n> + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple\n> + * 'writes' using this ioctl are necessary. The last packet is indicated\n> + * by the length being smaller than the PTM_STATE_BLOB_SIZE.\n> + * The very first packet may have a length indicator of '0' enabling\n> + * a write() with all the bytes from a buffer. If the write() interface\n> + * is used, a final ioctl with a non-full buffer must be made to indicate\n> + * that all data were transferred (a write with 0 bytes would not work).\n> + */\n> +struct ptm_setstate {\n> +    union {\n> +        struct {\n> +            uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */\n> +            uint32_t type;        /* which blob to set */\n> +            uint32_t length;      /* length of the data;\n> +                                     use 0 on the first packet to\n> +                                     transfer using write() */\n> +            uint8_t data[PTM_STATE_BLOB_SIZE];\n> +        } req; /* request */\n> +        struct {\n> +            ptm_res tpm_result;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +/*\n> + * PTM_GET_CONFIG: Data structure to get runtime configuration information\n> + * such as which keys are applied.\n> + */\n> +struct ptm_getconfig {\n> +    union {\n> +        struct {\n> +            ptm_res tpm_result;\n> +            uint32_t flags;\n> +        } resp; /* response */\n> +    } u;\n> +};\n> +\n> +#define PTM_CONFIG_FLAG_FILE_KEY        0x1\n> +#define PTM_CONFIG_FLAG_MIGRATION_KEY   0x2\n> +\n> +\n> +typedef uint64_t ptm_cap;\n> +typedef struct ptm_est ptm_est;\n> +typedef struct ptm_reset_est ptm_reset_est;\n> +typedef struct ptm_loc ptm_loc;\n> +typedef struct ptm_hdata ptm_hdata;\n> +typedef struct ptm_init ptm_init;\n> +typedef struct ptm_getstate ptm_getstate;\n> +typedef struct ptm_setstate ptm_setstate;\n> +typedef struct ptm_getconfig ptm_getconfig;\n> +\n> +/* capability flags returned by PTM_GET_CAPABILITY */\n> +#define PTM_CAP_INIT               (1)\n> +#define PTM_CAP_SHUTDOWN           (1 << 1)\n> +#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)\n> +#define PTM_CAP_SET_LOCALITY       (1 << 3)\n> +#define PTM_CAP_HASHING            (1 << 4)\n> +#define PTM_CAP_CANCEL_TPM_CMD     (1 << 5)\n> +#define PTM_CAP_STORE_VOLATILE     (1 << 6)\n> +#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)\n> +#define PTM_CAP_GET_STATEBLOB      (1 << 8)\n> +#define PTM_CAP_SET_STATEBLOB      (1 << 9)\n> +#define PTM_CAP_STOP               (1 << 10)\n> +#define PTM_CAP_GET_CONFIG         (1 << 11)\n> +#define PTM_CAP_SET_DATAFD         (1 << 12)\n> +\n> +enum {\n> +    PTM_GET_CAPABILITY     = _IOR('P', 0, ptm_cap),\n> +    PTM_INIT               = _IOWR('P', 1, ptm_init),\n> +    PTM_SHUTDOWN           = _IOR('P', 2, ptm_res),\n> +    PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),\n> +    PTM_SET_LOCALITY       = _IOWR('P', 4, ptm_loc),\n> +    PTM_HASH_START         = _IOR('P', 5, ptm_res),\n> +    PTM_HASH_DATA          = _IOWR('P', 6, ptm_hdata),\n> +    PTM_HASH_END           = _IOR('P', 7, ptm_res),\n> +    PTM_CANCEL_TPM_CMD     = _IOR('P', 8, ptm_res),\n> +    PTM_STORE_VOLATILE     = _IOR('P', 9, ptm_res),\n> +    PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),\n> +    PTM_GET_STATEBLOB      = _IOWR('P', 11, ptm_getstate),\n> +    PTM_SET_STATEBLOB      = _IOWR('P', 12, ptm_setstate),\n> +    PTM_STOP               = _IOR('P', 13, ptm_res),\n> +    PTM_GET_CONFIG         = _IOR('P', 14, ptm_getconfig),\n> +    PTM_SET_DATAFD         = _IOR('P', 15, ptm_res),\n> +};\n> +\n> +/*\n> + * Commands used by the non-CUSE TPMs\n> + *\n> + * All messages container big-endian data.\n> + *\n> + * The return messages only contain the 'resp' part of the unions\n> + * in the data structures above. Besides that the limits in the\n> + * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data\n> + * and ptm_set_state:u.req.data) are 0xffffffff.\n> + */\n> +enum {\n> +    CMD_GET_CAPABILITY = 1,\n> +    CMD_INIT,\n> +    CMD_SHUTDOWN,\n> +    CMD_GET_TPMESTABLISHED,\n> +    CMD_SET_LOCALITY,\n> +    CMD_HASH_START,\n> +    CMD_HASH_DATA,\n> +    CMD_HASH_END,\n> +    CMD_CANCEL_TPM_CMD,\n> +    CMD_STORE_VOLATILE,\n> +    CMD_RESET_TPMESTABLISHED,\n> +    CMD_GET_STATEBLOB,\n> +    CMD_SET_STATEBLOB,\n> +    CMD_STOP,\n> +    CMD_GET_CONFIG,\n> +    CMD_SET_DATAFD\n> +};\n> +\n> +#endif /* _TPM_IOCTL_H */\n> diff --git a/qapi/tpm.json b/qapi/tpm.json\n> index e8b2d8d..7093f26 100644\n> --- a/qapi/tpm.json\n> +++ b/qapi/tpm.json\n> @@ -39,10 +39,12 @@\n>  # An enumeration of TPM types\n>  #\n>  # @passthrough: TPM passthrough type\n> +# @emulator: Software Emulator TPM type\n> +#            Since: 2.11\n>  #\n>  # Since: 1.5\n>  ##\n> -{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }\n> +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }\n>\n>  ##\n>  # @query-tpm-types:\n> @@ -56,7 +58,7 @@\n>  # Example:\n>  #\n>  # -> { \"execute\": \"query-tpm-types\" }\n> -# <- { \"return\": [ \"passthrough\" ] }\n> +# <- { \"return\": [ \"passthrough\", \"emulator\" ] }\n>  #\n>  ##\n>  { 'command': 'query-tpm-types', 'returns': ['TpmType'] }\n> @@ -77,16 +79,29 @@\n>                                               '*cancel-path' : 'str'} }\n>\n>  ##\n> +# @TPMEmulatorOptions:\n> +#\n> +# Information about the TPM emulator type\n> +#\n> +# @chardev: Name of a unix socket chardev\n> +#\n> +# Since: 2.11\n> +##\n> +{ 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' } }\n> +\n> +##\n>  # @TpmTypeOptions:\n>  #\n>  # A union referencing different TPM backend types' configuration options\n>  #\n>  # @type: 'passthrough' The configuration options for the TPM passthrough type\n> +#        'emulator' The configuration options for TPM emulator backend type\n>  #\n>  # Since: 1.5\n>  ##\n>  { 'union': 'TpmTypeOptions',\n> -   'data': { 'passthrough' : 'TPMPassthroughOptions' } }\n> +   'data': { 'passthrough' : 'TPMPassthroughOptions',\n> +             'emulator': 'TPMEmulatorOptions' } }\n>\n>  ##\n>  # @TPMInfo:\n> diff --git a/qemu-options.hx b/qemu-options.hx\n> index 77859a2..1e93e53 100644\n> --- a/qemu-options.hx\n> +++ b/qemu-options.hx\n> @@ -3121,7 +3121,9 @@ DEF(\"tpmdev\", HAS_ARG, QEMU_OPTION_tpmdev, \\\n>      \"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\\n\"\n>      \"                use path to provide path to a character device; default is /dev/tpm0\\n\"\n>      \"                use cancel-path to provide path to TPM's cancel sysfs entry; if\\n\"\n> -    \"                not provided it will be searched for in /sys/class/misc/tpm?/device\\n\",\n> +    \"                not provided it will be searched for in /sys/class/misc/tpm?/device\\n\"\n> +    \"-tpmdev emulator,id=id,chardev=dev\\n\"\n> +    \"                configure the TPM device using chardev backend\\n\",\n>      QEMU_ARCH_ALL)\n>  STEXI\n>\n> @@ -3130,8 +3132,8 @@ The general form of a TPM device option is:\n>\n>  @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]\n>  @findex -tpmdev\n> -Backend type must be:\n> -@option{passthrough}.\n> +Backend type must be either one of the following:\n> +@option{passthrough}, @option{emulator}.\n>\n>  The specific backend type will determine the applicable options.\n>  The @code{-tpmdev} option creates the TPM backend and requires a\n> @@ -3181,6 +3183,20 @@ To create a passthrough TPM use the following two options:\n>  Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by\n>  @code{tpmdev=tpm0} in the device option.\n>\n> +@item -tpmdev emulator, id=@var{id}, chardev=@var{dev}\n> +\n> +(Linux-host only) Enable access to a TPM emulator using Unix domain socket based\n> +chardev backend.\n> +\n> +@option{chardev} specifies the unique ID of a character device backend that provides connection to the software TPM server.\n> +\n> +To create a TPM emulator backend device with chardev socket backend:\n> +@example\n> +\n> +-chardev socket,id=chrtpm,path=/tmp/swtpm-ctrl -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0\n> +\n> +@end example\n> +\n>  @end table\n>\n>  ETEXI\n> --\n> 2.7.4\n>","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"ky96m+la\"; dkim-atps=neutral"],"Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y0bvY4Dv8z9s7g\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 25 Sep 2017 04:53:12 +1000 (AEST)","from localhost ([::1]:39084 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dwC1d-0001bV-OQ\n\tfor incoming@patchwork.ozlabs.org; Sun, 24 Sep 2017 14:53:09 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:39906)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <marcandre.lureau@gmail.com>) id 1dwC1I-0001bD-SJ\n\tfor qemu-devel@nongnu.org; Sun, 24 Sep 2017 14:52:52 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <marcandre.lureau@gmail.com>) id 1dwC1E-0007cj-FJ\n\tfor qemu-devel@nongnu.org; Sun, 24 Sep 2017 14:52:48 -0400","from mail-oi0-x22c.google.com ([2607:f8b0:4003:c06::22c]:54259)\n\tby eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16)\n\t(Exim 4.71) (envelope-from <marcandre.lureau@gmail.com>)\n\tid 1dwC1E-0007bz-4y\n\tfor qemu-devel@nongnu.org; Sun, 24 Sep 2017 14:52:44 -0400","by mail-oi0-x22c.google.com with SMTP id j126so4310687oia.10\n\tfor <qemu-devel@nongnu.org>; Sun, 24 Sep 2017 11:52:42 -0700 (PDT)","by 10.58.17.173 with HTTP; Sun, 24 Sep 2017 11:52:40 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=mime-version:in-reply-to:references:from:date:message-id:subject:to\n\t:cc:content-transfer-encoding;\n\tbh=rEgoaUaO6mXgEfdJgSlegaNVr8QsoLzlfXFq37TKUHo=;\n\tb=ky96m+laYSbHRpm8n7m4mgVFmHG8gF5NQwP3UD6l90+LH4WQHbW/qQ5GhoeY8Egxi7\n\tkl0SfwmFtCVXaIw/NqMla8SvsA/kpCtI9ZdJ8D4B4zOevH6ds/Wz8OCas0eyWixkOhcU\n\t/wma9/nb4uKclQGdBkOjx7SKOJ6Z/44gjrB1r9YBgs1jITq9Mqyf+Mno+nDTX1xhzW6m\n\tUdh8NI6VFgYNf7C1odN40Fua9FywTHj+ddSxwOZ8VUVLvCCqERv27wSYDiNR0gEyv0k2\n\t/DOt0HDn9Srswpz3XUCgc++jzTooLOGosffa98bp93k4C5zNdvYbmeoLiqMvrUq9wLyr\n\tkoEg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:in-reply-to:references:from:date\n\t:message-id:subject:to:cc:content-transfer-encoding;\n\tbh=rEgoaUaO6mXgEfdJgSlegaNVr8QsoLzlfXFq37TKUHo=;\n\tb=rJcCdIU+sMuxwH/biqOtxbrXbERvEpBFThVLL1adtOGZkFz+hIk9juDIVE6qLORpBo\n\t4LGM2YhFeIIHJKxrG5gjlnCfaHPxRJQm5GrNzO0VYwbrRPMFWuqVZOssPmQJjIZR2Kyx\n\t80iuln8J3OFUfwbZo5zFN9wCrtUfU8QCW3VF2GrevlGbq6bv7TiYjAAIgAxhwgLoQYdi\n\tWP5ESTFp49jIqtSpZHSkYWKynf8dO0elT/5DCXG2I0oGoaUZGLNl9jErSokC171hk1v4\n\tGDm4/Q+YbnAkKCoH9ILBn80/KWlVsGZEr+aaolnjiG4Unze9spUHU2wo8nFnp3L8qsay\n\tuOhg==","X-Gm-Message-State":"AHPjjUh/0J0BYXhoYr7eNozHiiCM83J+ZqJ2/ZggYm3WtmQJBlla21/5\n\t7mHLb40PHCxKut/q1m/GDaQnmnUeHEVtAvFkO18=","X-Google-Smtp-Source":"AOwi7QDZAJ1w7WiUrIkRxJOrZVG+raok++mknwvFRfJAv3qTJVhBM0IRuMqIw4Pg92yR6bLHStVnLyZagx7kA0cgC8A=","X-Received":"by 10.202.235.5 with SMTP id j5mr5587444oih.304.1506279160645;\n\tSun, 24 Sep 2017 11:52:40 -0700 (PDT)","MIME-Version":"1.0","In-Reply-To":"<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>","From":"=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@gmail.com>","Date":"Sun, 24 Sep 2017 20:52:40 +0200","Message-ID":"<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>","To":"Amarnath Valluri <amarnath.valluri@intel.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-detected-operating-system":"by eggs.gnu.org: Genre and OS details not\n\trecognized.","X-Received-From":"2607:f8b0:4003:c06::22c","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"Markus Armbruster <armbru@redhat.com>, QEMU <qemu-devel@nongnu.org>,\n\t\"Dr. David Alan Gilbert\" <dgilbert@redhat.com>,\n\tStefan Berger <stefanb@linux.vnet.ibm.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}},{"id":1774324,"web_url":"http://patchwork.ozlabs.org/comment/1774324/","msgid":"<30e3f38b-2a3f-fb6c-91c7-fc740766d755@linux.vnet.ibm.com>","list_archive_url":null,"date":"2017-09-25T00:35:55","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":6671,"url":"http://patchwork.ozlabs.org/api/people/6671/","name":"Stefan Berger","email":"stefanb@linux.vnet.ibm.com"},"content":"On 09/24/2017 02:52 PM, Marc-André Lureau wrote:\n> Hi\n>\n> Thanks for the nice update, removing the exec() code, using chardev\n> and a private socketpair. Some comments below:\n>\n> On Fri, Sep 22, 2017 at 2:33 PM, Amarnath Valluri\n> <amarnath.valluri@intel.com> wrote:\n>> This change introduces a new TPM backend driver that can communicate with\n>> swtpm(software TPM emulator) using unix domain socket interface. QEMU talks to\n>> TPM emulator using socket based chardev backend device.\n>>\n>> Swtpm uses two Unix sockets for communications, one for plain TPM commands and\n>> responses, and one for out-of-band control messages. QEMU passes data socket\n>> been used over the control channel.\n>>\n>> The swtpm and associated tools can be found here:\n>>      https://github.com/stefanberger/swtpm\n>>\n>> The swtpm's control channel protocol specification can be found here:\n>>      https://github.com/stefanberger/swtpm/wiki/Control-Channel-Specification\n>>\n>> Usage:\n>>      # setup TPM state directory\n>>      mkdir /tmp/mytpm\n>>      chown -R tss:root /tmp/mytpm\n>>      /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek\n>>\n>>      # Ask qemu to use TPM emulator with given tpm state directory\n>>      qemu-system-x86_64 \\\n>>          [...] \\\n>>          -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \\\n>>          -tpmdev emulator,id=tpm0,chardev=chrtpm \\\n>>          -device tpm-tis,tpmdev=tpm0 \\\n>>          [...]\n>>\n>> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>\n>> ---\n>>   configure             |  15 +-\n>>   hmp.c                 |   5 +\n>>   hw/tpm/Makefile.objs  |   1 +\n>>   hw/tpm/tpm_emulator.c | 649 ++++++++++++++++++++++++++++++++++++++++++++++++++\n>>   hw/tpm/tpm_ioctl.h    | 246 +++++++++++++++++++\n>>   qapi/tpm.json         |  21 +-\n>>   qemu-options.hx       |  22 +-\n>>   7 files changed, 950 insertions(+), 9 deletions(-)\n>>   create mode 100644 hw/tpm/tpm_emulator.c\n>>   create mode 100644 hw/tpm/tpm_ioctl.h\n>>\n>> diff --git a/configure b/configure\n>> index cb0f7ed..ce2df2d 100755\n>> --- a/configure\n>> +++ b/configure\n>> @@ -3461,10 +3461,15 @@ fi\n>>   ##########################################\n>>   # TPM passthrough is only on x86 Linux\n>>\n>> -if test \"$targetos\" = Linux && test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\n>> -  tpm_passthrough=$tpm\n>> +if test \"$targetos\" = Linux; then\n>> +  tpm_emulator=$tpm\n>> +  if test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\n>> +    tpm_passthrough=$tpm\n>> +  else\n>> +    tpm_passthrough=no\n>> +  fi\n>>   else\n>> -  tpm_passthrough=no\n>> +  tpm_emulator=no\n>>   fi\n>>\n>>   ##########################################\n>> @@ -5359,6 +5364,7 @@ echo \"gcov enabled      $gcov\"\n>>   echo \"TPM support       $tpm\"\n>>   echo \"libssh2 support   $libssh2\"\n>>   echo \"TPM passthrough   $tpm_passthrough\"\n>> +echo \"TPM emulator      $tpm_emulator\"\n>>   echo \"QOM debugging     $qom_cast_debug\"\n>>   echo \"Live block migration $live_block_migration\"\n>>   echo \"lzo support       $lzo\"\n>> @@ -5943,6 +5949,9 @@ if test \"$tpm\" = \"yes\"; then\n>>     if test \"$tpm_passthrough\" = \"yes\"; then\n>>       echo \"CONFIG_TPM_PASSTHROUGH=y\" >> $config_host_mak\n>>     fi\n>> +  if test \"$tpm_emulator\" = \"yes\"; then\n>> +    echo \"CONFIG_TPM_EMULATOR=y\" >> $config_host_mak\n> It shouldn't require Linux, but posix (and I assume a port to other\n> systems isn't impossible). same for build-sys / help / comments.\n>\n>> +  fi\n>>   fi\n>>\n>>   echo \"TRACE_BACKENDS=$trace_backends\" >> $config_host_mak\n>> diff --git a/hmp.c b/hmp.c\n>> index cf62b2e..7e69eca 100644\n>> --- a/hmp.c\n>> +++ b/hmp.c\n>> @@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)\n>>       Error *err = NULL;\n>>       unsigned int c = 0;\n>>       TPMPassthroughOptions *tpo;\n>> +    TPMEmulatorOptions *teo;\n>>\n>>       info_list = qmp_query_tpm(&err);\n>>       if (err) {\n>> @@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)\n>>                              tpo->has_cancel_path ? \",cancel-path=\" : \"\",\n>>                              tpo->has_cancel_path ? tpo->cancel_path : \"\");\n>>               break;\n>> +        case TPM_TYPE_EMULATOR:\n>> +            teo = ti->options->u.emulator.data;\n>> +            monitor_printf(mon, \",chardev=%s\", teo->chardev);\n>> +            break;\n>>           case TPM_TYPE__MAX:\n>>               break;\n>>           }\n>> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs\n>> index 64cecc3..41f0b7a 100644\n>> --- a/hw/tpm/Makefile.objs\n>> +++ b/hw/tpm/Makefile.objs\n>> @@ -1,2 +1,3 @@\n>>   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o\n>>   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o\n>> +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o\n>> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c\n>> new file mode 100644\n>> index 0000000..c02bbe2\n>> --- /dev/null\n>> +++ b/hw/tpm/tpm_emulator.c\n>> @@ -0,0 +1,649 @@\n>> +/*\n>> + *  emulator TPM driver\n>> + *\n>> + *  Copyright (c) 2017 Intel Corporation\n>> + *  Author: Amarnath Valluri <amarnath.valluri@intel.com>\n>> + *\n>> + *  Copyright (c) 2010 - 2013 IBM Corporation\n>> + *  Authors:\n>> + *    Stefan Berger <stefanb@us.ibm.com>\n>> + *\n>> + *  Copyright (C) 2011 IAIK, Graz University of Technology\n>> + *    Author: Andreas Niederl\n>> + *\n>> + * This library is free software; you can redistribute it and/or\n>> + * modify it under the terms of the GNU Lesser General Public\n>> + * License as published by the Free Software Foundation; either\n>> + * version 2 of the License, or (at your option) any later version.\n>> + *\n>> + * This library is distributed in the hope that it will be useful,\n>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of\n>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n>> + * Lesser General Public License for more details.\n>> + *\n>> + * You should have received a copy of the GNU Lesser General Public\n>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>\n>> + *\n>> + */\n>> +\n>> +#include \"qemu/osdep.h\"\n>> +#include \"qemu/error-report.h\"\n>> +#include \"qemu/sockets.h\"\n>> +#include \"io/channel-socket.h\"\n>> +#include \"sysemu/tpm_backend.h\"\n>> +#include \"tpm_int.h\"\n>> +#include \"hw/hw.h\"\n>> +#include \"hw/i386/pc.h\"\n>> +#include \"tpm_util.h\"\n>> +#include \"tpm_ioctl.h\"\n>> +#include \"migration/blocker.h\"\n>> +#include \"qapi/error.h\"\n>> +#include \"chardev/char-fe.h\"\n>> +\n>> +#include <fcntl.h>\n>> +#include <sys/types.h>\n>> +#include <sys/stat.h>\n>> +#include <stdio.h>\n>> +\n>> +#define DEBUG_TPM 0\n>> +\n>> +#define DPRINT(fmt, ...) do { \\\n>> +    if (DEBUG_TPM) { \\\n>> +        fprintf(stderr, fmt, ## __VA_ARGS__); \\\n>> +    } \\\n>> +} while (0);\n>> +\n>> +#define DPRINTF(fmt, ...) DPRINT(\"tpm-emulator: \"fmt\"\\n\", __VA_ARGS__)\n> I would define a single DPRINTF() (& drop DPRINT usage below)\n>\n>\n>> +\n>> +#define TYPE_TPM_EMULATOR \"tpm-emulator\"\n>> +#define TPM_EMULATOR(obj) \\\n>> +    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)\n>> +\n>> +#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))\n>> +\n>> +static const TPMDriverOps tpm_emulator_driver;\n>> +\n>> +/* data structures */\n>> +typedef struct TPMEmulator {\n>> +    TPMBackend parent;\n>> +\n>> +    TPMEmulatorOptions *options;\n> Contrary to my comment on previous patch, I realize it is convenient\n> to have a qapi pointer here, so you can use the free visitor later.\n>\n>> +    CharBackend ctrl_dev;\n> ctrl_chr perhaps? or just chr or be (the most common name in other devices).\n>\n>> +    QIOChannel *data_ioc;\n>> +    bool op_executing;\n>> +    bool op_canceled;\n> I think those 2 fields can be dropped, see below.\n\nI agree. It's not necessary for the emulator driver to keep track of \nthese states.\n\n\n>\n>> +    bool had_startup_error;\n> I think some little refactoring could remove the whole\n> had_startup_error() backend & callback before or after the series.\n> tpm_backend_startup_tpm() already returns an error code.  device or\n> common backend code could handle & remember that.\n>\n>> +    TPMVersion tpm_version;\n> This is probably worth to consider in common code instead, but let's\n> not worry about it.\n>\n>> +    ptm_cap caps; /* capabilities of the TPM */\n>> +    uint8_t cur_locty_number; /* last set locality */\n>> +    QemuMutex state_lock;\n>> +    Error *migration_blocker;\n>> +} TPMEmulator;\n>> +\n>> +\n>> +static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long cmd, void *msg,\n>> +                                size_t msg_len_in, size_t msg_len_out)\n>> +{\n>> +    uint32_t cmd_no = cpu_to_be32(cmd);\n>> +    ssize_t n = sizeof(uint32_t) + msg_len_in;\n>> +    uint8_t *buf = NULL;\n>> +\n>> +    buf = (uint8_t *)malloc(n);\n> could be g_alloca() instead. Alternatively, why not call 2 write() instead?\n\nI think for swtpm the commands should arrive in one chunk.\n\n\n>\n> none of the casts in this function are necessary, please remove them.\n>\n>> +    memcpy(buf, &cmd_no, sizeof(cmd_no));\n>> +    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);\n>> +\n>> +    n += qemu_chr_fe_write_all(dev, (const uint8_t *)buf, n);\n> weird\n>\n>> +    free(buf);\n>> +\n>> +    if (n > 0) {\n> with the n += above, you'll get interesting behaviour :)\n>\n> You probably want to check if any write above failed, and return early\n> for the error case.\n>\n> Please improve the error handling in this function\n>\n>> +        if (msg_len_out > 0) {\n>> +            n = qemu_chr_fe_read_all(dev, (uint8_t *)msg, msg_len_out);\n>> +            /* simulate ioctl return value */\n>> +            if (n > 0) {\n>> +                n = 0;\n>> +            }\n>> +        } else {\n>> +            n = 0;\n>> +        }\n>> +    }\n>> +    return n;\n>> +}\n>> +\n>> +static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,\n> tpm_pt was tpm_passthrough I suppose.\n>\n> Please rename tpm_pt tpm_emu (or I would suggest \"self\", but this\n> isn't common name in qemu code - it's actually common in a close\n> c-object world., and it is quite convenient...)\n>\n>> +                                     const uint8_t *in, uint32_t in_len,\n>> +                                     uint8_t *out, uint32_t out_len,\n>> +                                     bool *selftest_done)\n>> +{\n>> +    ssize_t ret;\n>> +    bool is_selftest = false;\n>> +    const struct tpm_resp_hdr *hdr = NULL;\n>> +    Error *err = NULL;\n>> +\n>> +    tpm_pt->op_canceled = false;\n>> +    tpm_pt->op_executing = true;\n>> +    if (selftest_done) {\n>> +        *selftest_done = false;\n>> +        is_selftest = tpm_util_is_selftest(in, in_len);\n>> +    }\n>> +\n>> +    ret = qio_channel_write(tpm_pt->data_ioc, (char *)in, in_len, &err);\n> hmm, too bad qio_channel_write() doesn't take a void *\n>\n> why not write_all()?\n>\n>> +    if (ret != in_len || err) {\n>> +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n> I don't think ECANCELED make sense for emulator code.\n>\n>> +            error_report(\"tpm-emulator: error while transmitting data \"\n>> +                         \"to TPM: %s\", err ? error_get_pretty(err) : \"\");\n>> +            error_free(err);\n>> +        }\n>> +        goto err_exit;\n>> +    }\n>> +\n>> +    tpm_pt->op_executing = false;\n>> +\n>> +    ret = qio_channel_read(tpm_pt->data_ioc, (char *)out, out_len, &err);\n>> +    if (ret < 0 || err) {\n> read_all() ?\n>\n>> +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n>> +            error_report(\"tpm-emulator: error while reading data from \"\n>> +                         \"TPM: %s\", err ? error_get_pretty(err) : \"\");\n>> +            error_free(err);\n>> +        }\n>> +    } else if (ret >= sizeof(*hdr)) {\n>> +        hdr = (struct tpm_resp_hdr *)out;\n>> +    }\n>> +\n>> +    if (!hdr || be32_to_cpu(hdr->len) != ret) {\n>> +        error_report(\"tpm-emulator: received invalid response \"\n>> +                     \"packet from TPM with length :%ld\", ret);\n>> +        ret = -1;\n>> +        goto err_exit;\n>> +    }\n>> +\n>> +    if (is_selftest) {\n>> +        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);\n>> +    }\n>> +\n>> +    return 0;\n>> +\n>> +err_exit:\n>> +    if (ret < 0) {\n>> +        tpm_util_write_fatal_error_response(out, out_len);\n>> +    }\n>> +\n>> +    tpm_pt->op_executing = false;\n>> +\n>> +    return ret;\n>> +}\n>> +\n>> +static int tpm_emulator_set_locality(TPMEmulator *tpm_pt, uint8_t locty_number)\n>> +{\n>> +    ptm_loc loc;\n>> +\n>> +    DPRINTF(\"%s : locality: 0x%x\", __func__, locty_number);\n>> +\n>> +    if (tpm_pt->cur_locty_number != locty_number) {\n> return early instead if ==, to avoid code indent etc\n>\n>> +        DPRINTF(\"setting locality : 0x%x\", locty_number);\n>> +        loc.u.req.loc = locty_number;\n> This number isn't set in be like the rest of the protocol?\n>\n>> +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_LOCALITY, &loc,\n>> +                             sizeof(loc), sizeof(loc)) < 0) {\n>> +            error_report(\"tpm-emulator: could not set locality : %s\",\n>> +                         strerror(errno));\n>> +            return -1;\n>> +        }\n>> +        loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);\n>> +        if (loc.u.resp.tpm_result != 0) {\n>> +            error_report(\"tpm-emulator: TPM result for set locality : 0x%x\",\n>> +                         loc.u.resp.tpm_result);\n>> +            return -1;\n>> +        }\n>> +        tpm_pt->cur_locty_number = locty_number;\n>> +    }\n>> +    return 0;\n>> +}\n>> +\n>> +static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +    TPMLocality *locty = NULL;\n>> +    bool selftest_done = false;\n>> +\n>> +    DPRINTF(\"processing command type %d\", cmd);\n>> +\n>> +    switch (cmd) {\n>> +    case TPM_BACKEND_CMD_PROCESS_CMD:\n>> +        qemu_mutex_lock(&tpm_pt->state_lock);\n>> +        locty = tb->tpm_state->locty_data;\n>> +        if (tpm_emulator_set_locality(tpm_pt,\n>> +                                      tb->tpm_state->locty_number) < 0) {\n>> +            tpm_util_write_fatal_error_response(locty->r_buffer.buffer,\n>> +                                           locty->r_buffer.size);\n> return / goto here instead of else.\n>\n>> +        } else {\n>> +            tpm_emulator_unix_tx_bufs(tpm_pt, locty->w_buffer.buffer,\n>> +                                              locty->w_offset,\n>> +                                              locty->r_buffer.buffer,\n>> +                                              locty->r_buffer.size,\n>> +                                              &selftest_done);\n> no error handling?\n>\n>> +        }\n>> +\n>> +        tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,\n>> +                               selftest_done);\n>> +        qemu_mutex_unlock(&tpm_pt->state_lock);\n>> +\n>> +        break;\n>> +    case TPM_BACKEND_CMD_INIT:\n>> +    case TPM_BACKEND_CMD_END:\n>> +    case TPM_BACKEND_CMD_TPM_RESET:\n>> +        /* nothing to do */\n>> +        break;\n>> +    }\n>> +}\n>> +\n>> +/*\n>> + * Gracefully shut down the external unixio TPM\n>> + */\n>> +static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)\n>> +{\n>> +    ptm_res res;\n>> +\n>> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SHUTDOWN, &res, 0,\n>> +                         sizeof(res)) < 0) {\n>> +        error_report(\"tpm-emulator: Could not cleanly shutdown the TPM: %s\",\n>> +                     strerror(errno));\n>> +    } else if (res != 0) {\n>> +        error_report(\"tpm-emulator: TPM result for sutdown: 0x%x\",\n>> +                     be32_to_cpu(res));\n>> +    }\n>> +}\n>> +\n>> +static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)\n>> +{\n>> +    DPRINTF(\"%s\", __func__);\n>> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_GET_CAPABILITY,\n>> +                         &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) < 0) {\n>> +        error_report(\"tpm-emulator: probing failed : %s\", strerror(errno));\n>> +        return -1;\n>> +    }\n>> +\n>> +    tpm_pt->caps = be64_to_cpu(tpm_pt->caps);\n>> +\n>> +    DPRINTF(\"capbilities : 0x%lx\", tpm_pt->caps);\n>> +\n>> +    return 0;\n>> +}\n>> +\n>> +static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)\n>> +{\n>> +    ptm_cap caps = 0;\n>> +    const char *tpm = NULL;\n>> +\n>> +    /* check for min. required capabilities */\n>> +    switch (tpm_pt->tpm_version) {\n>> +    case TPM_VERSION_1_2:\n>> +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |\n>> +               PTM_CAP_SET_LOCALITY;\n>> +        tpm = \"1.2\";\n>> +        break;\n>> +    case TPM_VERSION_2_0:\n>> +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |\n>> +               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED;\n>> +        tpm = \"2\";\n>> +        break;\n>> +    case TPM_VERSION_UNSPEC:\n>> +        error_report(\"tpm-emulator: TPM version has not been set\");\n>> +        return -1;\n>> +    }\n>> +\n>> +    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {\n>> +        error_report(\"tpm-emulator: TPM does not implement minimum set of \"\n>> +                     \"required capabilities for TPM %s (0x%x)\", tpm, (int)caps);\n>> +        return -1;\n>> +    }\n>> +\n>> +    return 0;\n>> +}\n>> +\n>> +static int tpm_emulator_startup_tpm(TPMBackend *tb)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +    ptm_init init;\n>> +    ptm_res res;\n>> +\n>> +    DPRINTF(\"%s\", __func__);\n>> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_INIT, &init, sizeof(init),\n>> +                         sizeof(init)) < 0) {\n>> +        error_report(\"tpm-emulator: could not send INIT: %s\",\n>> +                     strerror(errno));\n>> +        goto err_exit;\n>> +    }\n>> +\n>> +    res = be32_to_cpu(init.u.resp.tpm_result);\n>> +    if (res) {\n>> +        error_report(\"tpm-emulator: TPM result for CMD_INIT: 0x%x\", res);\n>> +        goto err_exit;\n>> +    }\n>> +    return 0;\n>> +\n>> +err_exit:\n>> +    tpm_pt->had_startup_error = true;\n>> +    return -1;\n>> +}\n>> +\n>> +static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +    ptm_est est;\n>> +\n>> +    DPRINTF(\"%s\", __func__);\n>> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_GET_TPMESTABLISHED, &est, 0,\n>> +                         sizeof(est)) < 0) {\n>> +        error_report(\"tpm-emulator: Could not get the TPM established flag: %s\",\n>> +                     strerror(errno));\n>> +        return false;\n>> +    }\n>> +    DPRINTF(\"established flag: %0x\", est.u.resp.bit);\n>> +\n>> +    return (est.u.resp.bit != 0);\n>> +}\n>> +\n>> +static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,\n>> +                                                   uint8_t locty)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +    ptm_reset_est reset_est;\n>> +    ptm_res res;\n>> +\n>> +    /* only a TPM 2.0 will support this */\n>> +    if (tpm_pt->tpm_version == TPM_VERSION_2_0) {\n>> +        reset_est.u.req.loc = tpm_pt->cur_locty_number;\n>> +\n>> +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_RESET_TPMESTABLISHED,\n>> +                                 &reset_est, sizeof(reset_est),\n>> +                                 sizeof(reset_est)) < 0) {\n>> +            error_report(\"tpm-emulator: Could not reset the establishment bit: \"\n>> +                          \"%s\", strerror(errno));\n>> +            return -1;\n>> +        }\n>> +\n>> +        res = be32_to_cpu(reset_est.u.resp.tpm_result);\n>> +        if (res) {\n>> +            error_report(\"tpm-emulator: TPM result for rest establixhed flag: \"\n>> +                         \"0x%x\", res);\n>> +            return -1;\n>> +        }\n>> +    }\n>> +\n>> +    return 0;\n>> +}\n>> +\n>> +static bool tpm_emulator_had_startup_error(TPMBackend *tb)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +\n>> +    return tpm_pt->had_startup_error;\n>> +}\n>> +\n>> +static void tpm_emulator_cancel_cmd(TPMBackend *tb)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +    ptm_res res;\n>> +\n>> +    /*\n>> +     * As of Linux 3.7 the tpm_tis driver does not properly cancel\n>> +     * commands on all TPM manufacturers' TPMs.\n>> +     * Only cancel if we're busy so we don't cancel someone else's\n>> +     * command, e.g., a command executed on the host.\n>> +     */\n>> +    if (tpm_pt->op_executing) {\n> The field is set in the worker thread. This is racy. Fortunately this\n> is not relevant for emulator, I think you can simply drop that check\n> and the variable. Stefan should confirm though.\n>\n>> +        if (TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, PTM_CAP_CANCEL_TPM_CMD)) {\n>> +            if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_CANCEL_TPM_CMD,\n>> +                                     &res, 0, sizeof(res)) < 0) {\n>> +                error_report(\"tpm-emulator: Could not cancel command: %s\",\n>> +                             strerror(errno));\n>> +            } else if (res != 0) {\n>> +                error_report(\"tpm-emulator: Failed to cancel TPM: 0x%x\",\n>> +                             be32_to_cpu(res));\n>> +            } else {\n>> +                tpm_pt->op_canceled = true;\n>> +            }\n>> +        }\n>> +    }\n>> +}\n>> +\n>> +static void tpm_emulator_reset(TPMBackend *tb)\n>> +{\n>> +    DPRINTF(\"%s\", __func__);\n>> +\n>> +    tpm_emulator_cancel_cmd(tb);\n>> +}\n>> +\n>> +static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +\n>> +    return tpm_pt->tpm_version;\n>> +}\n>> +\n>> +static void tpm_emulator_block_migration(TPMEmulator *tpm_pt)\n>> +{\n>> +    Error *err = NULL;\n>> +\n>> +    error_setg(&tpm_pt->migration_blocker,\n>> +               \"Migration disabled: TPM emulator not yet migratable\");\n>> +    migrate_add_blocker(tpm_pt->migration_blocker, &err);\n>> +    if (err) {\n>> +        error_free(err);\n> probably better to report_err it instead\n>\n>> +        error_free(tpm_pt->migration_blocker);\n>> +        tpm_pt->migration_blocker = NULL;\n> and return an error code.\n>\n>> +    }\n>> +}\n>> +\n>> +static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_pt)\n>> +{\n>> +    ptm_res res;\n>> +    Error *err = NULL;\n>> +    int fds[2] = { -1, -1 };\n>> +\n>> +    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {\n>> +        error_report(\"tpm-emulator: Failed to create socketpair\");\n>> +        return -1;\n>> +    }\n>> +\n>> +    qemu_chr_fe_set_msgfds(&tpm_pt->ctrl_dev, fds + 1, 1);\n>> +\n>> +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_DATAFD, &res, 0,\n>> +                    sizeof(res)) || res != 0) {\n> Yay! for making life easier and hiding a protocol detail.\n>\n>> +        error_report(\"tpm-emulator: Failed to send CMD_SET_DATAFD: %s\",\n>> +                     strerror(errno));\n>> +        goto err_exit;\n>> +    }\n>> +\n>> +    tpm_pt->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));\n>> +    if (err) {\n>> +        error_report(\"tpm-emulator: Failed to create io channel : %s\",\n>> +                       error_get_pretty(err));\n> error_prepend()?\n>\n>> +        error_free(err);\n>> +        goto err_exit;\n>> +    }\n> close fds[1] ?\n>\n>> +\n>> +    return 0;\n>> +\n>> +err_exit:\n>> +    closesocket(fds[0]);\n>> +    closesocket(fds[1]);\n>> +    return -1;\n>> +}\n>> +\n>> +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt, QemuOpts *opts)\n>> +{\n>> +    const char *value;\n>> +\n>> +    value = qemu_opt_get(opts, \"chardev\");\n>> +    if (value) {\n>> +        Error *err = NULL;\n>> +        Chardev *dev = qemu_chr_find(value);\n>> +\n>> +        tpm_pt->options->chardev = g_strdup(value);\n>> +\n>> +        if (!dev || !qemu_chr_fe_init(&tpm_pt->ctrl_dev, dev, &err)) {\n>> +            error_report(\"tpm-emulator: No valid chardev found at '%s': %s\",\n>> +                         value, err ? error_get_pretty(err) : \"\");\n>> +            error_free(err);\n> error_prepend\n>\n>> +            goto err;\n>> +        }\n>> +    }\n>> +\n>> +    if (tpm_emulator_prepare_data_fd(tpm_pt) < 0) {\n>> +        goto err;\n>> +    }\n>> +\n>> +    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used\n>> +     * by passthrough driver, which not yet using GIOChannel.\n>> +     */\n>> +    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_pt->data_ioc)->fd,\n>> +                             &tpm_pt->tpm_version)) {\n>> +        error_report(\"'%s' is not emulating TPM device. Error: %s\",\n>> +                      tpm_pt->options->chardev, strerror(errno));\n>> +        goto err;\n>> +    }\n>> +\n>> +    DPRINTF(\"TPM Version %s\", tpm_pt->tpm_version == TPM_VERSION_1_2 ? \"1.2\" :\n>> +             (tpm_pt->tpm_version == TPM_VERSION_2_0 ?  \"2.0\" : \"Unspecified\"));\n>> +\n>> +    if (tpm_emulator_probe_caps(tpm_pt) ||\n>> +        tpm_emulator_check_caps(tpm_pt)) {\n>> +        goto err;\n>> +    }\n>> +\n>> +    tpm_emulator_block_migration(tpm_pt);\n>> +\n>> +    return 0;\n>> +\n>> +err:\n>> +    DPRINT(\"Startup error\\n\");\n>> +    return -1;\n>> +}\n>> +\n>> +static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)\n>> +{\n>> +    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));\n>> +\n>> +    tb->id = g_strdup(id);\n>> +\n>> +    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {\n>> +        goto err_exit;\n>> +    }\n>> +\n>> +    return tb;\n>> +\n>> +err_exit:\n>> +    object_unref(OBJECT(tb));\n>> +\n>> +    return NULL;\n>> +}\n>> +\n>> +static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> +    TpmTypeOptions *options = NULL;\n>> +    TPMEmulatorOptions *eoptions = NULL;\n>> +\n>> +    eoptions = g_new0(TPMEmulatorOptions, 1);\n>> +    if (!eoptions) {\n>> +        return NULL;\n>> +    }\n>> +    DPRINTF(\"%s\", __func__);\n>> +\n>> +    eoptions->chardev = g_strdup(tpm_pt->options->chardev);\n>> +    options = g_new0(TpmTypeOptions, 1);\n>> +    if (!options) {\n>> +        qapi_free_TPMEmulatorOptions(eoptions);\n>> +        return NULL;\n>> +    }\n>> +\n>> +    options->type = TPM_TYPE_EMULATOR;\n>> +    options->u.emulator.data = eoptions;\n> I think this is a job for QAPI_CLONE.\n>\n>> +\n>> +    return options;\n>> +}\n>> +\n>> +static const QemuOptDesc tpm_emulator_cmdline_opts[] = {\n>> +    TPM_STANDARD_CMDLINE_OPTS,\n>> +    {\n>> +        .name = \"chardev\",\n>> +        .type = QEMU_OPT_STRING,\n>> +        .help = \"Character device to use for out-of-band control messages\",\n>> +    },\n>> +    { /* end of list */ },\n>> +};\n>> +\n>> +static const TPMDriverOps tpm_emulator_driver = {\n>> +    .type                     = TPM_TYPE_EMULATOR,\n>> +    .opts                     = tpm_emulator_cmdline_opts,\n>> +    .desc                     = \"TPM emulator backend driver\",\n>> +\n>> +    .create                   = tpm_emulator_create,\n>> +    .startup_tpm              = tpm_emulator_startup_tpm,\n>> +    .reset                    = tpm_emulator_reset,\n>> +    .had_startup_error        = tpm_emulator_had_startup_error,\n>> +    .cancel_cmd               = tpm_emulator_cancel_cmd,\n>> +    .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,\n>> +    .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,\n>> +    .get_tpm_version          = tpm_emulator_get_tpm_version,\n>> +    .get_tpm_options          = tpm_emulator_get_tpm_options,\n>> +};\n>> +\n>> +static void tpm_emulator_inst_init(Object *obj)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n>> +\n>> +    DPRINTF(\"%s\", __func__);\n>> +    tpm_pt->options = g_new0(TPMEmulatorOptions, 1);\n>> +    tpm_pt->op_executing = tpm_pt->op_canceled = false;\n>> +    tpm_pt->had_startup_error = false;\n>> +    tpm_pt->cur_locty_number = ~0;\n>> +    qemu_mutex_init(&tpm_pt->state_lock);\n>> +}\n>> +\n>> +static void tpm_emulator_inst_finalize(Object *obj)\n>> +{\n>> +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n>> +\n>> +    tpm_emulator_cancel_cmd(TPM_BACKEND(obj));\n>> +    tpm_emulator_shutdown(tpm_pt);\n>> +\n>> +    if (tpm_pt->data_ioc) {\n>> +        qio_channel_close(tpm_pt->data_ioc, NULL);\n>> +    }\n>> +\n>> +    qemu_chr_fe_deinit(&tpm_pt->ctrl_dev, false);\n>> +\n>> +    if (tpm_pt->options) {\n>> +        qapi_free_TPMEmulatorOptions(tpm_pt->options);\n>> +    }\n>> +\n>> +    if (tpm_pt->migration_blocker) {\n>> +        migrate_del_blocker(tpm_pt->migration_blocker);\n>> +        error_free(tpm_pt->migration_blocker);\n>> +    }\n>> +}\n>> +\n>> +static void tpm_emulator_class_init(ObjectClass *klass, void *data)\n>> +{\n>> +    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);\n>> +    tbc->ops = &tpm_emulator_driver;\n>> +    tbc->handle_request = tpm_emulator_handle_request;\n>> +}\n>> +\n>> +static const TypeInfo tpm_emulator_info = {\n>> +    .name = TYPE_TPM_EMULATOR,\n>> +    .parent = TYPE_TPM_BACKEND,\n>> +    .instance_size = sizeof(TPMEmulator),\n>> +    .class_init = tpm_emulator_class_init,\n>> +    .instance_init = tpm_emulator_inst_init,\n>> +    .instance_finalize = tpm_emulator_inst_finalize,\n>> +};\n>> +\n>> +static void tpm_emulator_register(void)\n>> +{\n>> +    type_register_static(&tpm_emulator_info);\n>> +    tpm_register_driver(&tpm_emulator_driver);\n>> +}\n>> +\n>> +type_init(tpm_emulator_register)\n>> diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h\n>> new file mode 100644\n>> index 0000000..33564b1\n>> --- /dev/null\n>> +++ b/hw/tpm/tpm_ioctl.h\n> This file is copied from swtpm project. Could swtpm have it installed\n> on system instead?\n\n\nI think we'll have to carry this file here for a while until swtpm is \npackaged and distros provide it.\n\n    Stefan","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":"ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y0lX10r9Xz9sMN\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 25 Sep 2017 10:36:46 +1000 (AEST)","from localhost ([::1]:40098 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dwHO6-0007fO-9g\n\tfor incoming@patchwork.ozlabs.org; Sun, 24 Sep 2017 20:36:42 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:47987)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <stefanb@linux.vnet.ibm.com>) id 1dwHNa-0007fC-Gk\n\tfor qemu-devel@nongnu.org; Sun, 24 Sep 2017 20:36:13 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <stefanb@linux.vnet.ibm.com>) id 1dwHNX-0005KU-9w\n\tfor qemu-devel@nongnu.org; Sun, 24 Sep 2017 20:36:10 -0400","from mx0a-001b2d01.pphosted.com ([148.163.156.1]:56828)\n\tby eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <stefanb@linux.vnet.ibm.com>)\n\tid 1dwHNW-0005KA-Sz\n\tfor qemu-devel@nongnu.org; Sun, 24 Sep 2017 20:36:07 -0400","from pps.filterd (m0098399.ppops.net [127.0.0.1])\n\tby mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv8P0Y9LV139946\n\tfor <qemu-devel@nongnu.org>; Sun, 24 Sep 2017 20:36:01 -0400","from e12.ny.us.ibm.com (e12.ny.us.ibm.com [129.33.205.202])\n\tby mx0a-001b2d01.pphosted.com with ESMTP id 2d6dn924yb-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <qemu-devel@nongnu.org>; Sun, 24 Sep 2017 20:36:01 -0400","from localhost\n\tby e12.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <qemu-devel@nongnu.org> from <stefanb@linux.vnet.ibm.com>;\n\tSun, 24 Sep 2017 20:35:59 -0400","from b01cxnp23033.gho.pok.ibm.com (9.57.198.28)\n\tby e12.ny.us.ibm.com (146.89.104.199) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tSun, 24 Sep 2017 20:35:56 -0400","from b01ledav003.gho.pok.ibm.com (b01ledav003.gho.pok.ibm.com\n\t[9.57.199.108])\n\tby b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP\n\tid v8P0ZuXD65863928; Mon, 25 Sep 2017 00:35:56 GMT","from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1])\n\tby IMSVA (Postfix) with ESMTP id 0FEEFB204E;\n\tSun, 24 Sep 2017 20:33:16 -0400 (EDT)","from sbct-3.pok.ibm.com (unknown [9.47.158.153])\n\tby b01ledav003.gho.pok.ibm.com (Postfix) with ESMTP id EB8AFB204D;\n\tSun, 24 Sep 2017 20:33:15 -0400 (EDT)"],"To":"=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@gmail.com>,\n\tAmarnath Valluri <amarnath.valluri@intel.com>","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>\n\t<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>","From":"Stefan Berger <stefanb@linux.vnet.ibm.com>","Date":"Sun, 24 Sep 2017 20:35:55 -0400","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101\n\tThunderbird/45.4.0","MIME-Version":"1.0","In-Reply-To":"<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>","Content-Type":"text/plain; charset=utf-8; format=flowed","X-TM-AS-GCONF":"00","x-cbid":"17092500-0048-0000-0000-000001EA3AA8","X-IBM-SpamModules-Scores":"","X-IBM-SpamModules-Versions":"BY=3.00007786; HX=3.00000241; KW=3.00000007;\n\tPH=3.00000004; SC=3.00000231; SDB=6.00921898; UDB=6.00463314;\n\tIPR=6.00702041; \n\tBA=6.00005602; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009;\n\tZB=6.00000000; \n\tZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00017261;\n\tXFM=3.00000015; UTC=2017-09-25 00:35:58","X-IBM-AV-DETECTION":"SAVI=unused REMOTE=unused XFE=unused","x-cbparentid":"17092500-0049-0000-0000-000042AA85F8","Message-Id":"<30e3f38b-2a3f-fb6c-91c7-fc740766d755@linux.vnet.ibm.com>","X-Proofpoint-Virus-Version":"vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-09-24_07:, , signatures=0","X-Proofpoint-Spam-Details":"rule=outbound_notspam policy=outbound score=0\n\tspamscore=0 suspectscore=2\n\tmalwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam\n\tadjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000\n\tdefinitions=main-1709250006","Content-Transfer-Encoding":"quoted-printable","X-MIME-Autoconverted":"from 8bit to quoted-printable by\n\tmx0a-001b2d01.pphosted.com id v8P0Y9LV139946","X-detected-operating-system":"by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy]","X-Received-From":"148.163.156.1","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"Markus Armbruster <armbru@redhat.com>,\n\t\"Dr. David Alan Gilbert\" <dgilbert@redhat.com>,\n\tQEMU <qemu-devel@nongnu.org>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}},{"id":1775407,"web_url":"http://patchwork.ozlabs.org/comment/1775407/","msgid":"<1506427596.5843.104.camel@intel.com>","list_archive_url":null,"date":"2017-09-26T12:05:11","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":71320,"url":"http://patchwork.ozlabs.org/api/people/71320/","name":"Valluri, Amarnath","email":"amarnath.valluri@intel.com"},"content":"Hi Marc,\r\n\r\nThanks for your time reviewing this patchset. Please find my inline\r\ncomments.\r\n\r\nOn Sun, 2017-09-24 at 20:52 +0200, Marc-André Lureau wrote:\r\n> Hi\r\n> \r\n> Thanks for the nice update, removing the exec() code, using chardev\r\n> and a private socketpair. Some comments below:\r\n> \r\n> On Fri, Sep 22, 2017 at 2:33 PM, Amarnath Valluri\r\n> <amarnath.valluri@intel.com> wrote:\r\n> > \r\n> > This change introduces a new TPM backend driver that can\r\n> > communicate with\r\n> > swtpm(software TPM emulator) using unix domain socket interface.\r\n> > QEMU talks to\r\n> > TPM emulator using socket based chardev backend device.\r\n> > \r\n> > Swtpm uses two Unix sockets for communications, one for plain TPM\r\n> > commands and\r\n> > responses, and one for out-of-band control messages. QEMU passes\r\n> > data socket\r\n> > been used over the control channel.\r\n> > \r\n> > The swtpm and associated tools can be found here:\r\n> >     https://github.com/stefanberger/swtpm\r\n> > \r\n> > The swtpm's control channel protocol specification can be found\r\n> > here:\r\n> >     https://github.com/stefanberger/swtpm/wiki/Control-Channel-Spec\r\n> > ification\r\n> > \r\n> > Usage:\r\n> >     # setup TPM state directory\r\n> >     mkdir /tmp/mytpm\r\n> >     chown -R tss:root /tmp/mytpm\r\n> >     /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek\r\n> > \r\n> >     # Ask qemu to use TPM emulator with given tpm state directory\r\n> >     qemu-system-x86_64 \\\r\n> >         [...] \\\r\n> >         -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \\\r\n> >         -tpmdev emulator,id=tpm0,chardev=chrtpm \\\r\n> >         -device tpm-tis,tpmdev=tpm0 \\\r\n> >         [...]\r\n> > \r\n> > Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>\r\n> > ---\r\n> >  configure             |  15 +-\r\n> >  hmp.c                 |   5 +\r\n> >  hw/tpm/Makefile.objs  |   1 +\r\n> >  hw/tpm/tpm_emulator.c | 649\r\n> > ++++++++++++++++++++++++++++++++++++++++++++++++++\r\n> >  hw/tpm/tpm_ioctl.h    | 246 +++++++++++++++++++\r\n> >  qapi/tpm.json         |  21 +-\r\n> >  qemu-options.hx       |  22 +-\r\n> >  7 files changed, 950 insertions(+), 9 deletions(-)\r\n> >  create mode 100644 hw/tpm/tpm_emulator.c\r\n> >  create mode 100644 hw/tpm/tpm_ioctl.h\r\n> > \r\n> > diff --git a/configure b/configure\r\n> > index cb0f7ed..ce2df2d 100755\r\n> > --- a/configure\r\n> > +++ b/configure\r\n> > @@ -3461,10 +3461,15 @@ fi\r\n> >  ##########################################\r\n> >  # TPM passthrough is only on x86 Linux\r\n> > \r\n> > -if test \"$targetos\" = Linux && test \"$cpu\" = i386 -o \"$cpu\" =\r\n> > x86_64; then\r\n> > -  tpm_passthrough=$tpm\r\n> > +if test \"$targetos\" = Linux; then\r\n> > +  tpm_emulator=$tpm\r\n> > +  if test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\r\n> > +    tpm_passthrough=$tpm\r\n> > +  else\r\n> > +    tpm_passthrough=no\r\n> > +  fi\r\n> >  else\r\n> > -  tpm_passthrough=no\r\n> > +  tpm_emulator=no\r\n> >  fi\r\n> > \r\n> >  ##########################################\r\n> > @@ -5359,6 +5364,7 @@ echo \"gcov enabled      $gcov\"\r\n> >  echo \"TPM support       $tpm\"\r\n> >  echo \"libssh2 support   $libssh2\"\r\n> >  echo \"TPM passthrough   $tpm_passthrough\"\r\n> > +echo \"TPM emulator      $tpm_emulator\"\r\n> >  echo \"QOM debugging     $qom_cast_debug\"\r\n> >  echo \"Live block migration $live_block_migration\"\r\n> >  echo \"lzo support       $lzo\"\r\n> > @@ -5943,6 +5949,9 @@ if test \"$tpm\" = \"yes\"; then\r\n> >    if test \"$tpm_passthrough\" = \"yes\"; then\r\n> >      echo \"CONFIG_TPM_PASSTHROUGH=y\" >> $config_host_mak\r\n> >    fi\r\n> > +  if test \"$tpm_emulator\" = \"yes\"; then\r\n> > +    echo \"CONFIG_TPM_EMULATOR=y\" >> $config_host_mak\r\n> It shouldn't require Linux, but posix (and I assume a port to other\r\n> systems isn't impossible). same for build-sys / help / comments.\r\nI agree, Can you suggest, what is the Qemu way of limiting this to\r\n'posix'.\r\n> \r\n> > \r\n> > +  fi\r\n> >  fi\r\n> > \r\n> >  echo \"TRACE_BACKENDS=$trace_backends\" >> $config_host_mak\r\n> > diff --git a/hmp.c b/hmp.c\r\n> > index cf62b2e..7e69eca 100644\r\n> > --- a/hmp.c\r\n> > +++ b/hmp.c\r\n> > @@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict\r\n> > *qdict)\r\n> >      Error *err = NULL;\r\n> >      unsigned int c = 0;\r\n> >      TPMPassthroughOptions *tpo;\r\n> > +    TPMEmulatorOptions *teo;\r\n> > \r\n> >      info_list = qmp_query_tpm(&err);\r\n> >      if (err) {\r\n> > @@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const QDict\r\n> > *qdict)\r\n> >                             tpo->has_cancel_path ? \",cancel-path=\"\r\n> > : \"\",\r\n> >                             tpo->has_cancel_path ? tpo->cancel_path \r\n> > : \"\");\r\n> >              break;\r\n> > +        case TPM_TYPE_EMULATOR:\r\n> > +            teo = ti->options->u.emulator.data;\r\n> > +            monitor_printf(mon, \",chardev=%s\", teo->chardev);\r\n> > +            break;\r\n> >          case TPM_TYPE__MAX:\r\n> >              break;\r\n> >          }\r\n> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs\r\n> > index 64cecc3..41f0b7a 100644\r\n> > --- a/hw/tpm/Makefile.objs\r\n> > +++ b/hw/tpm/Makefile.objs\r\n> > @@ -1,2 +1,3 @@\r\n> >  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o\r\n> >  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o\r\n> > tpm_util.o\r\n> > +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o\r\n> > diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c\r\n> > new file mode 100644\r\n> > index 0000000..c02bbe2\r\n> > --- /dev/null\r\n> > +++ b/hw/tpm/tpm_emulator.c\r\n> > @@ -0,0 +1,649 @@\r\n> > +/*\r\n> > + *  emulator TPM driver\r\n> > + *\r\n> > + *  Copyright (c) 2017 Intel Corporation\r\n> > + *  Author: Amarnath Valluri <amarnath.valluri@intel.com>\r\n> > + *\r\n> > + *  Copyright (c) 2010 - 2013 IBM Corporation\r\n> > + *  Authors:\r\n> > + *    Stefan Berger <stefanb@us.ibm.com>\r\n> > + *\r\n> > + *  Copyright (C) 2011 IAIK, Graz University of Technology\r\n> > + *    Author: Andreas Niederl\r\n> > + *\r\n> > + * This library is free software; you can redistribute it and/or\r\n> > + * modify it under the terms of the GNU Lesser General Public\r\n> > + * License as published by the Free Software Foundation; either\r\n> > + * version 2 of the License, or (at your option) any later\r\n> > version.\r\n> > + *\r\n> > + * This library is distributed in the hope that it will be useful,\r\n> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n> > GNU\r\n> > + * Lesser General Public License for more details.\r\n> > + *\r\n> > + * You should have received a copy of the GNU Lesser General\r\n> > Public\r\n> > + * License along with this library; if not, see <http://www.gnu.or\r\n> > g/licenses/>\r\n> > + *\r\n> > + */\r\n> > +\r\n> > +#include \"qemu/osdep.h\"\r\n> > +#include \"qemu/error-report.h\"\r\n> > +#include \"qemu/sockets.h\"\r\n> > +#include \"io/channel-socket.h\"\r\n> > +#include \"sysemu/tpm_backend.h\"\r\n> > +#include \"tpm_int.h\"\r\n> > +#include \"hw/hw.h\"\r\n> > +#include \"hw/i386/pc.h\"\r\n> > +#include \"tpm_util.h\"\r\n> > +#include \"tpm_ioctl.h\"\r\n> > +#include \"migration/blocker.h\"\r\n> > +#include \"qapi/error.h\"\r\n> > +#include \"chardev/char-fe.h\"\r\n> > +\r\n> > +#include <fcntl.h>\r\n> > +#include <sys/types.h>\r\n> > +#include <sys/stat.h>\r\n> > +#include <stdio.h>\r\n> > +\r\n> > +#define DEBUG_TPM 0\r\n> > +\r\n> > +#define DPRINT(fmt, ...) do { \\\r\n> > +    if (DEBUG_TPM) { \\\r\n> > +        fprintf(stderr, fmt, ## __VA_ARGS__); \\\r\n> > +    } \\\r\n> > +} while (0);\r\n> > +\r\n> > +#define DPRINTF(fmt, ...) DPRINT(\"tpm-emulator: \"fmt\"\\n\",\r\n> > __VA_ARGS__)\r\n> I would define a single DPRINTF() (& drop DPRINT usage below)\r\nOk, will do\r\n> \r\n> \r\n> > \r\n> > +\r\n> > +#define TYPE_TPM_EMULATOR \"tpm-emulator\"\r\n> > +#define TPM_EMULATOR(obj) \\\r\n> > +    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)\r\n> > +\r\n> > +#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps &\r\n> > (cap)) == (cap))\r\n> > +\r\n> > +static const TPMDriverOps tpm_emulator_driver;\r\n> > +\r\n> > +/* data structures */\r\n> > +typedef struct TPMEmulator {\r\n> > +    TPMBackend parent;\r\n> > +\r\n> > +    TPMEmulatorOptions *options;\r\n> Contrary to my comment on previous patch, I realize it is convenient\r\n> to have a qapi pointer here, so you can use the free visitor later.\r\n> \r\n> > \r\n> > +    CharBackend ctrl_dev;\r\n> ctrl_chr perhaps? or just chr or be (the most common name in other\r\n> devices).\r\n> \r\n> > \r\n> > +    QIOChannel *data_ioc;\r\n> > +    bool op_executing;\r\n> > +    bool op_canceled;\r\n> I think those 2 fields can be dropped, see below.\r\n> \r\n> > \r\n> > +    bool had_startup_error;\r\n> I think some little refactoring could remove the whole\r\n> had_startup_error() backend & callback before or after the series.\r\n> tpm_backend_startup_tpm() already returns an error code.  device or\r\n> common backend code could handle & remember that.\r\nYes, i agree, we can avoid had_startup_error() from DriverOps, i will\r\ndo this.\r\n> \r\n> > \r\n> > +    TPMVersion tpm_version;\r\n> This is probably worth to consider in common code instead, but let's\r\n> not worry about it.\r\n> \r\n> > \r\n> > +    ptm_cap caps; /* capabilities of the TPM */\r\n> > +    uint8_t cur_locty_number; /* last set locality */\r\n> > +    QemuMutex state_lock;\r\n> > +    Error *migration_blocker;\r\n> > +} TPMEmulator;\r\n> > +\r\n> > +\r\n> > +static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long\r\n> > cmd, void *msg,\r\n> > +                                size_t msg_len_in, size_t\r\n> > msg_len_out)\r\n> > +{\r\n> > +    uint32_t cmd_no = cpu_to_be32(cmd);\r\n> > +    ssize_t n = sizeof(uint32_t) + msg_len_in;\r\n> > +    uint8_t *buf = NULL;\r\n> > +\r\n> > +    buf = (uint8_t *)malloc(n);\r\n> could be g_alloca() instead. Alternatively, why not call 2 write()\r\n> instead?\r\n> \r\n> none of the casts in this function are necessary, please remove them.\r\nOk, will change to aclloca()\r\n> \r\n> > \r\n> > +    memcpy(buf, &cmd_no, sizeof(cmd_no));\r\n> > +    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);\r\n> > +\r\n> > +    n += qemu_chr_fe_write_all(dev, (const uint8_t *)buf, n);\r\n> weird\r\n> \r\n> > \r\n> > +    free(buf);\r\n> > +\r\n> > +    if (n > 0) {\r\n> with the n += above, you'll get interesting behaviour :)\r\nYa, it was typo :)\r\n> \r\n> You probably want to check if any write above failed, and return\r\n> early\r\n> for the error case.\r\n> \r\n> Please improve the error handling in this function\r\n> \r\n> > \r\n> > +        if (msg_len_out > 0) {\r\n> > +            n = qemu_chr_fe_read_all(dev, (uint8_t *)msg,\r\n> > msg_len_out);\r\n> > +            /* simulate ioctl return value */\r\n> > +            if (n > 0) {\r\n> > +                n = 0;\r\n> > +            }\r\n> > +        } else {\r\n> > +            n = 0;\r\n> > +        }\r\n> > +    }\r\n> > +    return n;\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,\r\n> tpm_pt was tpm_passthrough I suppose.\r\n> \r\n> Please rename tpm_pt tpm_emu (or I would suggest \"self\", but this\r\n> isn't common name in qemu code - it's actually common in a close\r\n> c-object world., and it is quite convenient...)\r\nMy interpretation about _pt was 'pointer' ;-) i will consider your\r\nsuggetion.\r\n> \r\n> > \r\n> > +                                     const uint8_t *in, uint32_t\r\n> > in_len,\r\n> > +                                     uint8_t *out, uint32_t\r\n> > out_len,\r\n> > +                                     bool *selftest_done)\r\n> > +{\r\n> > +    ssize_t ret;\r\n> > +    bool is_selftest = false;\r\n> > +    const struct tpm_resp_hdr *hdr = NULL;\r\n> > +    Error *err = NULL;\r\n> > +\r\n> > +    tpm_pt->op_canceled = false;\r\n> > +    tpm_pt->op_executing = true;\r\n> > +    if (selftest_done) {\r\n> > +        *selftest_done = false;\r\n> > +        is_selftest = tpm_util_is_selftest(in, in_len);\r\n> > +    }\r\n> > +\r\n> > +    ret = qio_channel_write(tpm_pt->data_ioc, (char *)in, in_len,\r\n> > &err);\r\n> hmm, too bad qio_channel_write() doesn't take a void *\r\n> \r\n> why not write_all()?\r\nAgreed\r\n> \r\n> > \r\n> > +    if (ret != in_len || err) {\r\n> > +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\r\n> I don't think ECANCELED make sense for emulator code.\r\n> \r\n> > \r\n> > +            error_report(\"tpm-emulator: error while transmitting\r\n> > data \"\r\n> > +                         \"to TPM: %s\", err ? error_get_pretty(err)\r\n> > : \"\");\r\n> > +            error_free(err);\r\n> > +        }\r\n> > +        goto err_exit;\r\n> > +    }\r\n> > +\r\n> > +    tpm_pt->op_executing = false;\r\n> > +\r\n> > +    ret = qio_channel_read(tpm_pt->data_ioc, (char *)out, out_len,\r\n> > &err);\r\n> > +    if (ret < 0 || err) {\r\n> read_all() ?\r\nThe issue with read_all() is it does not return the no of bytes it\r\nread, so i would like to stict to _read()\r\n> \r\n> > \r\n> > +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\r\n> > +            error_report(\"tpm-emulator: error while reading data\r\n> > from \"\r\n> > +                         \"TPM: %s\", err ? error_get_pretty(err) :\r\n> > \"\");\r\n> > +            error_free(err);\r\n> > +        }\r\n> > +    } else if (ret >= sizeof(*hdr)) {\r\n> > +        hdr = (struct tpm_resp_hdr *)out;\r\n> > +    }\r\n> > +\r\n> > +    if (!hdr || be32_to_cpu(hdr->len) != ret) {\r\n> > +        error_report(\"tpm-emulator: received invalid response \"\r\n> > +                     \"packet from TPM with length :%ld\", ret);\r\n> > +        ret = -1;\r\n> > +        goto err_exit;\r\n> > +    }\r\n> > +\r\n> > +    if (is_selftest) {\r\n> > +        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);\r\n> > +    }\r\n> > +\r\n> > +    return 0;\r\n> > +\r\n> > +err_exit:\r\n> > +    if (ret < 0) {\r\n> > +        tpm_util_write_fatal_error_response(out, out_len);\r\n> > +    }\r\n> > +\r\n> > +    tpm_pt->op_executing = false;\r\n> > +\r\n> > +    return ret;\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_set_locality(TPMEmulator *tpm_pt, uint8_t\r\n> > locty_number)\r\n> > +{\r\n> > +    ptm_loc loc;\r\n> > +\r\n> > +    DPRINTF(\"%s : locality: 0x%x\", __func__, locty_number);\r\n> > +\r\n> > +    if (tpm_pt->cur_locty_number != locty_number) {\r\n> return early instead if ==, to avoid code indent etc\r\nOk\r\n> \r\n> > \r\n> > +        DPRINTF(\"setting locality : 0x%x\", locty_number);\r\n> > +        loc.u.req.loc = locty_number;\r\n> This number isn't set in be like the rest of the protocol?\r\nI doubt if i get ur point :(, can you please elaborate.\r\n> \r\n> > \r\n> > +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > CMD_SET_LOCALITY, &loc,\r\n> > +                             sizeof(loc), sizeof(loc)) < 0) {\r\n> > +            error_report(\"tpm-emulator: could not set locality :\r\n> > %s\",\r\n> > +                         strerror(errno));\r\n> > +            return -1;\r\n> > +        }\r\n> > +        loc.u.resp.tpm_result =\r\n> > be32_to_cpu(loc.u.resp.tpm_result);\r\n> > +        if (loc.u.resp.tpm_result != 0) {\r\n> > +            error_report(\"tpm-emulator: TPM result for set\r\n> > locality : 0x%x\",\r\n> > +                         loc.u.resp.tpm_result);\r\n> > +            return -1;\r\n> > +        }\r\n> > +        tpm_pt->cur_locty_number = locty_number;\r\n> > +    }\r\n> > +    return 0;\r\n> > +}\r\n> > +\r\n> > +static void tpm_emulator_handle_request(TPMBackend *tb,\r\n> > TPMBackendCmd cmd)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +    TPMLocality *locty = NULL;\r\n> > +    bool selftest_done = false;\r\n> > +\r\n> > +    DPRINTF(\"processing command type %d\", cmd);\r\n> > +\r\n> > +    switch (cmd) {\r\n> > +    case TPM_BACKEND_CMD_PROCESS_CMD:\r\n> > +        qemu_mutex_lock(&tpm_pt->state_lock);\r\n> > +        locty = tb->tpm_state->locty_data;\r\n> > +        if (tpm_emulator_set_locality(tpm_pt,\r\n> > +                                      tb->tpm_state->locty_number) \r\n> > < 0) {\r\n> > +            tpm_util_write_fatal_error_response(locty-\r\n> > >r_buffer.buffer,\r\n> > +                                           locty->r_buffer.size);\r\n> return / goto here instead of else.\r\nWe should not retrun from here, we have to propagte the error response\r\nto device, and unlock the state.\r\n> \r\n> > \r\n> > +        } else {\r\n> > +            tpm_emulator_unix_tx_bufs(tpm_pt, locty-\r\n> > >w_buffer.buffer,\r\n> > +                                              locty->w_offset,\r\n> > +                                              locty-\r\n> > >r_buffer.buffer,\r\n> > +                                              locty-\r\n> > >r_buffer.size,\r\n> > +                                              &selftest_done);\r\n> no error handling?\r\nThe error case is supposed to handle by device, where we are filling\r\ninto out buffer, using tpm_util_write_fatal_error_response().\r\n> \r\n> > \r\n> > +        }\r\n> > +\r\n> > +        tb->recv_data_callback(tb->tpm_state, tb->tpm_state-\r\n> > >locty_number,\r\n> > +                               selftest_done);\r\n> > +        qemu_mutex_unlock(&tpm_pt->state_lock);\r\n> > +\r\n> > +        break;\r\n> > +    case TPM_BACKEND_CMD_INIT:\r\n> > +    case TPM_BACKEND_CMD_END:\r\n> > +    case TPM_BACKEND_CMD_TPM_RESET:\r\n> > +        /* nothing to do */\r\n> > +        break;\r\n> > +    }\r\n> > +}\r\n> > +\r\n> > +/*\r\n> > + * Gracefully shut down the external unixio TPM\r\n> > + */\r\n> > +static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)\r\n> > +{\r\n> > +    ptm_res res;\r\n> > +\r\n> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SHUTDOWN,\r\n> > &res, 0,\r\n> > +                         sizeof(res)) < 0) {\r\n> > +        error_report(\"tpm-emulator: Could not cleanly shutdown the\r\n> > TPM: %s\",\r\n> > +                     strerror(errno));\r\n> > +    } else if (res != 0) {\r\n> > +        error_report(\"tpm-emulator: TPM result for sutdown: 0x%x\",\r\n> > +                     be32_to_cpu(res));\r\n> > +    }\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)\r\n> > +{\r\n> > +    DPRINTF(\"%s\", __func__);\r\n> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > CMD_GET_CAPABILITY,\r\n> > +                         &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) <\r\n> > 0) {\r\n> > +        error_report(\"tpm-emulator: probing failed : %s\",\r\n> > strerror(errno));\r\n> > +        return -1;\r\n> > +    }\r\n> > +\r\n> > +    tpm_pt->caps = be64_to_cpu(tpm_pt->caps);\r\n> > +\r\n> > +    DPRINTF(\"capbilities : 0x%lx\", tpm_pt->caps);\r\n> > +\r\n> > +    return 0;\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)\r\n> > +{\r\n> > +    ptm_cap caps = 0;\r\n> > +    const char *tpm = NULL;\r\n> > +\r\n> > +    /* check for min. required capabilities */\r\n> > +    switch (tpm_pt->tpm_version) {\r\n> > +    case TPM_VERSION_1_2:\r\n> > +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |\r\n> > PTM_CAP_GET_TPMESTABLISHED |\r\n> > +               PTM_CAP_SET_LOCALITY;\r\n> > +        tpm = \"1.2\";\r\n> > +        break;\r\n> > +    case TPM_VERSION_2_0:\r\n> > +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |\r\n> > PTM_CAP_GET_TPMESTABLISHED |\r\n> > +               PTM_CAP_SET_LOCALITY |\r\n> > PTM_CAP_RESET_TPMESTABLISHED;\r\n> > +        tpm = \"2\";\r\n> > +        break;\r\n> > +    case TPM_VERSION_UNSPEC:\r\n> > +        error_report(\"tpm-emulator: TPM version has not been\r\n> > set\");\r\n> > +        return -1;\r\n> > +    }\r\n> > +\r\n> > +    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {\r\n> > +        error_report(\"tpm-emulator: TPM does not implement minimum\r\n> > set of \"\r\n> > +                     \"required capabilities for TPM %s (0x%x)\",\r\n> > tpm, (int)caps);\r\n> > +        return -1;\r\n> > +    }\r\n> > +\r\n> > +    return 0;\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_startup_tpm(TPMBackend *tb)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +    ptm_init init;\r\n> > +    ptm_res res;\r\n> > +\r\n> > +    DPRINTF(\"%s\", __func__);\r\n> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_INIT, &init,\r\n> > sizeof(init),\r\n> > +                         sizeof(init)) < 0) {\r\n> > +        error_report(\"tpm-emulator: could not send INIT: %s\",\r\n> > +                     strerror(errno));\r\n> > +        goto err_exit;\r\n> > +    }\r\n> > +\r\n> > +    res = be32_to_cpu(init.u.resp.tpm_result);\r\n> > +    if (res) {\r\n> > +        error_report(\"tpm-emulator: TPM result for CMD_INIT:\r\n> > 0x%x\", res);\r\n> > +        goto err_exit;\r\n> > +    }\r\n> > +    return 0;\r\n> > +\r\n> > +err_exit:\r\n> > +    tpm_pt->had_startup_error = true;\r\n> > +    return -1;\r\n> > +}\r\n> > +\r\n> > +static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +    ptm_est est;\r\n> > +\r\n> > +    DPRINTF(\"%s\", __func__);\r\n> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > CMD_GET_TPMESTABLISHED, &est, 0,\r\n> > +                         sizeof(est)) < 0) {\r\n> > +        error_report(\"tpm-emulator: Could not get the TPM\r\n> > established flag: %s\",\r\n> > +                     strerror(errno));\r\n> > +        return false;\r\n> > +    }\r\n> > +    DPRINTF(\"established flag: %0x\", est.u.resp.bit);\r\n> > +\r\n> > +    return (est.u.resp.bit != 0);\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,\r\n> > +                                                   uint8_t locty)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +    ptm_reset_est reset_est;\r\n> > +    ptm_res res;\r\n> > +\r\n> > +    /* only a TPM 2.0 will support this */\r\n> > +    if (tpm_pt->tpm_version == TPM_VERSION_2_0) {\r\n> > +        reset_est.u.req.loc = tpm_pt->cur_locty_number;\r\n> > +\r\n> > +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > CMD_RESET_TPMESTABLISHED,\r\n> > +                                 &reset_est, sizeof(reset_est),\r\n> > +                                 sizeof(reset_est)) < 0) {\r\n> > +            error_report(\"tpm-emulator: Could not reset the\r\n> > establishment bit: \"\r\n> > +                          \"%s\", strerror(errno));\r\n> > +            return -1;\r\n> > +        }\r\n> > +\r\n> > +        res = be32_to_cpu(reset_est.u.resp.tpm_result);\r\n> > +        if (res) {\r\n> > +            error_report(\"tpm-emulator: TPM result for rest\r\n> > establixhed flag: \"\r\n> > +                         \"0x%x\", res);\r\n> > +            return -1;\r\n> > +        }\r\n> > +    }\r\n> > +\r\n> > +    return 0;\r\n> > +}\r\n> > +\r\n> > +static bool tpm_emulator_had_startup_error(TPMBackend *tb)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +\r\n> > +    return tpm_pt->had_startup_error;\r\n> > +}\r\n> > +\r\n> > +static void tpm_emulator_cancel_cmd(TPMBackend *tb)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +    ptm_res res;\r\n> > +\r\n> > +    /*\r\n> > +     * As of Linux 3.7 the tpm_tis driver does not properly cancel\r\n> > +     * commands on all TPM manufacturers' TPMs.\r\n> > +     * Only cancel if we're busy so we don't cancel someone else's\r\n> > +     * command, e.g., a command executed on the host.\r\n> > +     */\r\n> > +    if (tpm_pt->op_executing) {\r\n> The field is set in the worker thread. This is racy. Fortunately this\r\n> is not relevant for emulator, I think you can simply drop that check\r\n> and the variable. Stefan should confirm though.\r\n> \r\n> > \r\n> > +        if (TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt,\r\n> > PTM_CAP_CANCEL_TPM_CMD)) {\r\n> > +            if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > CMD_CANCEL_TPM_CMD,\r\n> > +                                     &res, 0, sizeof(res)) < 0) {\r\n> > +                error_report(\"tpm-emulator: Could not cancel\r\n> > command: %s\",\r\n> > +                             strerror(errno));\r\n> > +            } else if (res != 0) {\r\n> > +                error_report(\"tpm-emulator: Failed to cancel TPM:\r\n> > 0x%x\",\r\n> > +                             be32_to_cpu(res));\r\n> > +            } else {\r\n> > +                tpm_pt->op_canceled = true;\r\n> > +            }\r\n> > +        }\r\n> > +    }\r\n> > +}\r\n> > +\r\n> > +static void tpm_emulator_reset(TPMBackend *tb)\r\n> > +{\r\n> > +    DPRINTF(\"%s\", __func__);\r\n> > +\r\n> > +    tpm_emulator_cancel_cmd(tb);\r\n> > +}\r\n> > +\r\n> > +static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +\r\n> > +    return tpm_pt->tpm_version;\r\n> > +}\r\n> > +\r\n> > +static void tpm_emulator_block_migration(TPMEmulator *tpm_pt)\r\n> > +{\r\n> > +    Error *err = NULL;\r\n> > +\r\n> > +    error_setg(&tpm_pt->migration_blocker,\r\n> > +               \"Migration disabled: TPM emulator not yet\r\n> > migratable\");\r\n> > +    migrate_add_blocker(tpm_pt->migration_blocker, &err);\r\n> > +    if (err) {\r\n> > +        error_free(err);\r\n> probably better to report_err it instead\r\nOk\r\n> \r\n> > \r\n> > +        error_free(tpm_pt->migration_blocker);\r\n> > +        tpm_pt->migration_blocker = NULL;\r\n> and return an error code.\r\nWill do\r\n> \r\n> > \r\n> > +    }\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_pt)\r\n> > +{\r\n> > +    ptm_res res;\r\n> > +    Error *err = NULL;\r\n> > +    int fds[2] = { -1, -1 };\r\n> > +\r\n> > +    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {\r\n> > +        error_report(\"tpm-emulator: Failed to create socketpair\");\r\n> > +        return -1;\r\n> > +    }\r\n> > +\r\n> > +    qemu_chr_fe_set_msgfds(&tpm_pt->ctrl_dev, fds + 1, 1);\r\n> > +\r\n> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_DATAFD,\r\n> > &res, 0,\r\n> > +                    sizeof(res)) || res != 0) {\r\n> Yay! for making life easier and hiding a protocol detail.\r\n> \r\n> > \r\n> > +        error_report(\"tpm-emulator: Failed to send CMD_SET_DATAFD:\r\n> > %s\",\r\n> > +                     strerror(errno));\r\n> > +        goto err_exit;\r\n> > +    }\r\n> > +\r\n> > +    tpm_pt->data_ioc =\r\n> > QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));\r\n> > +    if (err) {\r\n> > +        error_report(\"tpm-emulator: Failed to create io channel :\r\n> > %s\",\r\n> > +                       error_get_pretty(err));\r\n> error_prepend()?\r\nOk\r\n> \r\n> > \r\n> > +        error_free(err);\r\n> > +        goto err_exit;\r\n> > +    }\r\n> close fds[1] ?\r\nI guess we are not supposed to close the other end of the\r\nsocketpair/pipe, as it is not forked process.\r\n> \r\n> > \r\n> > +\r\n> > +    return 0;\r\n> > +\r\n> > +err_exit:\r\n> > +    closesocket(fds[0]);\r\n> > +    closesocket(fds[1]);\r\n> > +    return -1;\r\n> > +}\r\n> > +\r\n> > +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt,\r\n> > QemuOpts *opts)\r\n> > +{\r\n> > +    const char *value;\r\n> > +\r\n> > +    value = qemu_opt_get(opts, \"chardev\");\r\n> > +    if (value) {\r\n> > +        Error *err = NULL;\r\n> > +        Chardev *dev = qemu_chr_find(value);\r\n> > +\r\n> > +        tpm_pt->options->chardev = g_strdup(value);\r\n> > +\r\n> > +        if (!dev || !qemu_chr_fe_init(&tpm_pt->ctrl_dev, dev,\r\n> > &err)) {\r\n> > +            error_report(\"tpm-emulator: No valid chardev found at\r\n> > '%s': %s\",\r\n> > +                         value, err ? error_get_pretty(err) : \"\");\r\n> > +            error_free(err);\r\n> error_prepend\r\nOk\r\n> \r\n> > \r\n> > +            goto err;\r\n> > +        }\r\n> > +    }\r\n> > +\r\n> > +    if (tpm_emulator_prepare_data_fd(tpm_pt) < 0) {\r\n> > +        goto err;\r\n> > +    }\r\n> > +\r\n> > +    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as\r\n> > it also used\r\n> > +     * by passthrough driver, which not yet using GIOChannel.\r\n> > +     */\r\n> > +    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_pt->data_ioc)-\r\n> > >fd,\r\n> > +                             &tpm_pt->tpm_version)) {\r\n> > +        error_report(\"'%s' is not emulating TPM device. Error:\r\n> > %s\",\r\n> > +                      tpm_pt->options->chardev, strerror(errno));\r\n> > +        goto err;\r\n> > +    }\r\n> > +\r\n> > +    DPRINTF(\"TPM Version %s\", tpm_pt->tpm_version ==\r\n> > TPM_VERSION_1_2 ? \"1.2\" :\r\n> > +             (tpm_pt->tpm_version == TPM_VERSION_2_0 ?  \"2.0\" :\r\n> > \"Unspecified\"));\r\n> > +\r\n> > +    if (tpm_emulator_probe_caps(tpm_pt) ||\r\n> > +        tpm_emulator_check_caps(tpm_pt)) {\r\n> > +        goto err;\r\n> > +    }\r\n> > +\r\n> > +    tpm_emulator_block_migration(tpm_pt);\r\n> > +\r\n> > +    return 0;\r\n> > +\r\n> > +err:\r\n> > +    DPRINT(\"Startup error\\n\");\r\n> > +    return -1;\r\n> > +}\r\n> > +\r\n> > +static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char\r\n> > *id)\r\n> > +{\r\n> > +    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));\r\n> > +\r\n> > +    tb->id = g_strdup(id);\r\n> > +\r\n> > +    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {\r\n> > +        goto err_exit;\r\n> > +    }\r\n> > +\r\n> > +    return tb;\r\n> > +\r\n> > +err_exit:\r\n> > +    object_unref(OBJECT(tb));\r\n> > +\r\n> > +    return NULL;\r\n> > +}\r\n> > +\r\n> > +static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend\r\n> > *tb)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > +    TpmTypeOptions *options = NULL;\r\n> > +    TPMEmulatorOptions *eoptions = NULL;\r\n> > +\r\n> > +    eoptions = g_new0(TPMEmulatorOptions, 1);\r\n> > +    if (!eoptions) {\r\n> > +        return NULL;\r\n> > +    }\r\n> > +    DPRINTF(\"%s\", __func__);\r\n> > +\r\n> > +    eoptions->chardev = g_strdup(tpm_pt->options->chardev);\r\n> > +    options = g_new0(TpmTypeOptions, 1);\r\n> > +    if (!options) {\r\n> > +        qapi_free_TPMEmulatorOptions(eoptions);\r\n> > +        return NULL;\r\n> > +    }\r\n> > +\r\n> > +    options->type = TPM_TYPE_EMULATOR;\r\n> > +    options->u.emulator.data = eoptions;\r\n> I think this is a job for QAPI_CLONE.\r\n> \r\n> > \r\n> > +\r\n> > +    return options;\r\n> > +}\r\n> > +\r\n> > +static const QemuOptDesc tpm_emulator_cmdline_opts[] = {\r\n> > +    TPM_STANDARD_CMDLINE_OPTS,\r\n> > +    {\r\n> > +        .name = \"chardev\",\r\n> > +        .type = QEMU_OPT_STRING,\r\n> > +        .help = \"Character device to use for out-of-band control\r\n> > messages\",\r\n> > +    },\r\n> > +    { /* end of list */ },\r\n> > +};\r\n> > +\r\n> > +static const TPMDriverOps tpm_emulator_driver = {\r\n> > +    .type                     = TPM_TYPE_EMULATOR,\r\n> > +    .opts                     = tpm_emulator_cmdline_opts,\r\n> > +    .desc                     = \"TPM emulator backend driver\",\r\n> > +\r\n> > +    .create                   = tpm_emulator_create,\r\n> > +    .startup_tpm              = tpm_emulator_startup_tpm,\r\n> > +    .reset                    = tpm_emulator_reset,\r\n> > +    .had_startup_error        = tpm_emulator_had_startup_error,\r\n> > +    .cancel_cmd               = tpm_emulator_cancel_cmd,\r\n> > +    .get_tpm_established_flag =\r\n> > tpm_emulator_get_tpm_established_flag,\r\n> > +    .reset_tpm_established_flag =\r\n> > tpm_emulator_reset_tpm_established_flag,\r\n> > +    .get_tpm_version          = tpm_emulator_get_tpm_version,\r\n> > +    .get_tpm_options          = tpm_emulator_get_tpm_options,\r\n> > +};\r\n> > +\r\n> > +static void tpm_emulator_inst_init(Object *obj)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\r\n> > +\r\n> > +    DPRINTF(\"%s\", __func__);\r\n> > +    tpm_pt->options = g_new0(TPMEmulatorOptions, 1);\r\n> > +    tpm_pt->op_executing = tpm_pt->op_canceled = false;\r\n> > +    tpm_pt->had_startup_error = false;\r\n> > +    tpm_pt->cur_locty_number = ~0;\r\n> > +    qemu_mutex_init(&tpm_pt->state_lock);\r\n> > +}\r\n> > +\r\n> > +static void tpm_emulator_inst_finalize(Object *obj)\r\n> > +{\r\n> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\r\n> > +\r\n> > +    tpm_emulator_cancel_cmd(TPM_BACKEND(obj));\r\n> > +    tpm_emulator_shutdown(tpm_pt);\r\n> > +\r\n> > +    if (tpm_pt->data_ioc) {\r\n> > +        qio_channel_close(tpm_pt->data_ioc, NULL);\r\n> > +    }\r\n> > +\r\n> > +    qemu_chr_fe_deinit(&tpm_pt->ctrl_dev, false);\r\n> > +\r\n> > +    if (tpm_pt->options) {\r\n> > +        qapi_free_TPMEmulatorOptions(tpm_pt->options);\r\n> > +    }\r\n> > +\r\n> > +    if (tpm_pt->migration_blocker) {\r\n> > +        migrate_del_blocker(tpm_pt->migration_blocker);\r\n> > +        error_free(tpm_pt->migration_blocker);\r\n> > +    }\r\n> > +}\r\n> > +\r\n> > +static void tpm_emulator_class_init(ObjectClass *klass, void\r\n> > *data)\r\n> > +{\r\n> > +    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);\r\n> > +    tbc->ops = &tpm_emulator_driver;\r\n> > +    tbc->handle_request = tpm_emulator_handle_request;\r\n> > +}\r\n> > +\r\n> > +static const TypeInfo tpm_emulator_info = {\r\n> > +    .name = TYPE_TPM_EMULATOR,\r\n> > +    .parent = TYPE_TPM_BACKEND,\r\n> > +    .instance_size = sizeof(TPMEmulator),\r\n> > +    .class_init = tpm_emulator_class_init,\r\n> > +    .instance_init = tpm_emulator_inst_init,\r\n> > +    .instance_finalize = tpm_emulator_inst_finalize,\r\n> > +};\r\n> > +\r\n> > +static void tpm_emulator_register(void)\r\n> > +{\r\n> > +    type_register_static(&tpm_emulator_info);\r\n> > +    tpm_register_driver(&tpm_emulator_driver);\r\n> > +}\r\n> > +\r\n> > +type_init(tpm_emulator_register)\r\n> > diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h\r\n> > new file mode 100644\r\n> > index 0000000..33564b1\r\n> > --- /dev/null\r\n> > +++ b/hw/tpm/tpm_ioctl.h\r\n> This file is copied from swtpm project. Could swtpm have it installed\r\n> on system instead?\r\n> \r\n> > \r\n> > @@ -0,0 +1,246 @@\r\n> > +/*\r\n> > + * tpm_ioctl.h\r\n> > + *\r\n> > + * (c) Copyright IBM Corporation 2014, 2015.\r\n> > + *\r\n> > + * This file is licensed under the terms of the 3-clause BSD\r\n> > license\r\n> > + */\r\n> > +#ifndef _TPM_IOCTL_H_\r\n> > +#define _TPM_IOCTL_H_\r\n> > +\r\n> > +#include <stdint.h>\r\n> > +#include <sys/uio.h>\r\n> > +#include <sys/types.h>\r\n> > +#include <sys/ioctl.h>\r\n> > +\r\n> > +/*\r\n> > + * Every response from a command involving a TPM command execution\r\n> > must hold\r\n> > + * the ptm_res as the first element.\r\n> > + * ptm_res corresponds to the error code of a command executed by\r\n> > the TPM.\r\n> > + */\r\n> > +\r\n> > +typedef uint32_t ptm_res;\r\n> > +\r\n> > +/* PTM_GET_TPMESTABLISHED: get the establishment bit */\r\n> > +struct ptm_est {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +            unsigned char bit; /* TPM established bit */\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +/* PTM_RESET_TPMESTABLISHED: reset establishment bit */\r\n> > +struct ptm_reset_est {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            uint8_t loc; /* locality to use */\r\n> > +        } req; /* request */\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +/* PTM_INIT */\r\n> > +struct ptm_init {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            uint32_t init_flags; /* see definitions below */\r\n> > +        } req; /* request */\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +/* above init_flags */\r\n> > +#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)\r\n> > +    /* delete volatile state file after reading it */\r\n> > +\r\n> > +/* PTM_SET_LOCALITY */\r\n> > +struct ptm_loc {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            uint8_t loc; /* locality to set */\r\n> > +        } req; /* request */\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +/* PTM_HASH_DATA: hash given data */\r\n> > +struct ptm_hdata {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            uint32_t length;\r\n> > +            uint8_t data[4096];\r\n> > +        } req; /* request */\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +/*\r\n> > + * size of the TPM state blob to transfer; x86_64 can handle 8k,\r\n> > + * ppc64le only ~7k; keep the response below a 4k page size\r\n> > + */\r\n> > +#define PTM_STATE_BLOB_SIZE (3 * 1024)\r\n> > +\r\n> > +/*\r\n> > + * The following is the data structure to get state blobs from the\r\n> > TPM.\r\n> > + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE,\r\n> > multiple reads\r\n> > + * with this ioctl and with adjusted offset are necessary. All\r\n> > bytes\r\n> > + * must be transferred and the transfer is done once the last byte\r\n> > has been\r\n> > + * returned.\r\n> > + * It is possible to use the read() interface for reading the\r\n> > data; however, the\r\n> > + * first bytes of the state blob will be part of the response to\r\n> > the ioctl(); a\r\n> > + * subsequent read() is only necessary if the total length\r\n> > (totlength) exceeds\r\n> > + * the number of received bytes. seek() is not supported.\r\n> > + */\r\n> > +struct ptm_getstate {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            uint32_t state_flags; /* may be:\r\n> > PTM_STATE_FLAG_DECRYPTED */\r\n> > +            uint32_t type;        /* which blob to pull */\r\n> > +            uint32_t offset;      /* offset from where to read */\r\n> > +        } req; /* request */\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +            uint32_t state_flags; /* may be:\r\n> > PTM_STATE_FLAG_ENCRYPTED */\r\n> > +            uint32_t totlength;   /* total length that will be\r\n> > transferred */\r\n> > +            uint32_t length;      /* number of bytes in following\r\n> > buffer */\r\n> > +            uint8_t  data[PTM_STATE_BLOB_SIZE];\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +/* TPM state blob types */\r\n> > +#define PTM_BLOB_TYPE_PERMANENT  1\r\n> > +#define PTM_BLOB_TYPE_VOLATILE   2\r\n> > +#define PTM_BLOB_TYPE_SAVESTATE  3\r\n> > +\r\n> > +/* state_flags above : */\r\n> > +#define PTM_STATE_FLAG_DECRYPTED     1 /* on input:  get decrypted\r\n> > state */\r\n> > +#define PTM_STATE_FLAG_ENCRYPTED     2 /* on output: state is\r\n> > encrypted */\r\n> > +\r\n> > +/*\r\n> > + * The following is the data structure to set state blobs in the\r\n> > TPM.\r\n> > + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE,\r\n> > multiple\r\n> > + * 'writes' using this ioctl are necessary. The last packet is\r\n> > indicated\r\n> > + * by the length being smaller than the PTM_STATE_BLOB_SIZE.\r\n> > + * The very first packet may have a length indicator of '0'\r\n> > enabling\r\n> > + * a write() with all the bytes from a buffer. If the write()\r\n> > interface\r\n> > + * is used, a final ioctl with a non-full buffer must be made to\r\n> > indicate\r\n> > + * that all data were transferred (a write with 0 bytes would not\r\n> > work).\r\n> > + */\r\n> > +struct ptm_setstate {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            uint32_t state_flags; /* may be\r\n> > PTM_STATE_FLAG_ENCRYPTED */\r\n> > +            uint32_t type;        /* which blob to set */\r\n> > +            uint32_t length;      /* length of the data;\r\n> > +                                     use 0 on the first packet to\r\n> > +                                     transfer using write() */\r\n> > +            uint8_t data[PTM_STATE_BLOB_SIZE];\r\n> > +        } req; /* request */\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +/*\r\n> > + * PTM_GET_CONFIG: Data structure to get runtime configuration\r\n> > information\r\n> > + * such as which keys are applied.\r\n> > + */\r\n> > +struct ptm_getconfig {\r\n> > +    union {\r\n> > +        struct {\r\n> > +            ptm_res tpm_result;\r\n> > +            uint32_t flags;\r\n> > +        } resp; /* response */\r\n> > +    } u;\r\n> > +};\r\n> > +\r\n> > +#define PTM_CONFIG_FLAG_FILE_KEY        0x1\r\n> > +#define PTM_CONFIG_FLAG_MIGRATION_KEY   0x2\r\n> > +\r\n> > +\r\n> > +typedef uint64_t ptm_cap;\r\n> > +typedef struct ptm_est ptm_est;\r\n> > +typedef struct ptm_reset_est ptm_reset_est;\r\n> > +typedef struct ptm_loc ptm_loc;\r\n> > +typedef struct ptm_hdata ptm_hdata;\r\n> > +typedef struct ptm_init ptm_init;\r\n> > +typedef struct ptm_getstate ptm_getstate;\r\n> > +typedef struct ptm_setstate ptm_setstate;\r\n> > +typedef struct ptm_getconfig ptm_getconfig;\r\n> > +\r\n> > +/* capability flags returned by PTM_GET_CAPABILITY */\r\n> > +#define PTM_CAP_INIT               (1)\r\n> > +#define PTM_CAP_SHUTDOWN           (1 << 1)\r\n> > +#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)\r\n> > +#define PTM_CAP_SET_LOCALITY       (1 << 3)\r\n> > +#define PTM_CAP_HASHING            (1 << 4)\r\n> > +#define PTM_CAP_CANCEL_TPM_CMD     (1 << 5)\r\n> > +#define PTM_CAP_STORE_VOLATILE     (1 << 6)\r\n> > +#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)\r\n> > +#define PTM_CAP_GET_STATEBLOB      (1 << 8)\r\n> > +#define PTM_CAP_SET_STATEBLOB      (1 << 9)\r\n> > +#define PTM_CAP_STOP               (1 << 10)\r\n> > +#define PTM_CAP_GET_CONFIG         (1 << 11)\r\n> > +#define PTM_CAP_SET_DATAFD         (1 << 12)\r\n> > +\r\n> > +enum {\r\n> > +    PTM_GET_CAPABILITY     = _IOR('P', 0, ptm_cap),\r\n> > +    PTM_INIT               = _IOWR('P', 1, ptm_init),\r\n> > +    PTM_SHUTDOWN           = _IOR('P', 2, ptm_res),\r\n> > +    PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),\r\n> > +    PTM_SET_LOCALITY       = _IOWR('P', 4, ptm_loc),\r\n> > +    PTM_HASH_START         = _IOR('P', 5, ptm_res),\r\n> > +    PTM_HASH_DATA          = _IOWR('P', 6, ptm_hdata),\r\n> > +    PTM_HASH_END           = _IOR('P', 7, ptm_res),\r\n> > +    PTM_CANCEL_TPM_CMD     = _IOR('P', 8, ptm_res),\r\n> > +    PTM_STORE_VOLATILE     = _IOR('P', 9, ptm_res),\r\n> > +    PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),\r\n> > +    PTM_GET_STATEBLOB      = _IOWR('P', 11, ptm_getstate),\r\n> > +    PTM_SET_STATEBLOB      = _IOWR('P', 12, ptm_setstate),\r\n> > +    PTM_STOP               = _IOR('P', 13, ptm_res),\r\n> > +    PTM_GET_CONFIG         = _IOR('P', 14, ptm_getconfig),\r\n> > +    PTM_SET_DATAFD         = _IOR('P', 15, ptm_res),\r\n> > +};\r\n> > +\r\n> > +/*\r\n> > + * Commands used by the non-CUSE TPMs\r\n> > + *\r\n> > + * All messages container big-endian data.\r\n> > + *\r\n> > + * The return messages only contain the 'resp' part of the unions\r\n> > + * in the data structures above. Besides that the limits in the\r\n> > + * buffers above (ptm_hdata:u.req.data and\r\n> > ptm_get_state:u.resp.data\r\n> > + * and ptm_set_state:u.req.data) are 0xffffffff.\r\n> > + */\r\n> > +enum {\r\n> > +    CMD_GET_CAPABILITY = 1,\r\n> > +    CMD_INIT,\r\n> > +    CMD_SHUTDOWN,\r\n> > +    CMD_GET_TPMESTABLISHED,\r\n> > +    CMD_SET_LOCALITY,\r\n> > +    CMD_HASH_START,\r\n> > +    CMD_HASH_DATA,\r\n> > +    CMD_HASH_END,\r\n> > +    CMD_CANCEL_TPM_CMD,\r\n> > +    CMD_STORE_VOLATILE,\r\n> > +    CMD_RESET_TPMESTABLISHED,\r\n> > +    CMD_GET_STATEBLOB,\r\n> > +    CMD_SET_STATEBLOB,\r\n> > +    CMD_STOP,\r\n> > +    CMD_GET_CONFIG,\r\n> > +    CMD_SET_DATAFD\r\n> > +};\r\n> > +\r\n> > +#endif /* _TPM_IOCTL_H */\r\n> > diff --git a/qapi/tpm.json b/qapi/tpm.json\r\n> > index e8b2d8d..7093f26 100644\r\n> > --- a/qapi/tpm.json\r\n> > +++ b/qapi/tpm.json\r\n> > @@ -39,10 +39,12 @@\r\n> >  # An enumeration of TPM types\r\n> >  #\r\n> >  # @passthrough: TPM passthrough type\r\n> > +# @emulator: Software Emulator TPM type\r\n> > +#            Since: 2.11\r\n> >  #\r\n> >  # Since: 1.5\r\n> >  ##\r\n> > -{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }\r\n> > +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }\r\n> > \r\n> >  ##\r\n> >  # @query-tpm-types:\r\n> > @@ -56,7 +58,7 @@\r\n> >  # Example:\r\n> >  #\r\n> >  # -> { \"execute\": \"query-tpm-types\" }\r\n> > -# <- { \"return\": [ \"passthrough\" ] }\r\n> > +# <- { \"return\": [ \"passthrough\", \"emulator\" ] }\r\n> >  #\r\n> >  ##\r\n> >  { 'command': 'query-tpm-types', 'returns': ['TpmType'] }\r\n> > @@ -77,16 +79,29 @@\r\n> >                                               '*cancel-path' :\r\n> > 'str'} }\r\n> > \r\n> >  ##\r\n> > +# @TPMEmulatorOptions:\r\n> > +#\r\n> > +# Information about the TPM emulator type\r\n> > +#\r\n> > +# @chardev: Name of a unix socket chardev\r\n> > +#\r\n> > +# Since: 2.11\r\n> > +##\r\n> > +{ 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' } }\r\n> > +\r\n> > +##\r\n> >  # @TpmTypeOptions:\r\n> >  #\r\n> >  # A union referencing different TPM backend types' configuration\r\n> > options\r\n> >  #\r\n> >  # @type: 'passthrough' The configuration options for the TPM\r\n> > passthrough type\r\n> > +#        'emulator' The configuration options for TPM emulator\r\n> > backend type\r\n> >  #\r\n> >  # Since: 1.5\r\n> >  ##\r\n> >  { 'union': 'TpmTypeOptions',\r\n> > -   'data': { 'passthrough' : 'TPMPassthroughOptions' } }\r\n> > +   'data': { 'passthrough' : 'TPMPassthroughOptions',\r\n> > +             'emulator': 'TPMEmulatorOptions' } }\r\n> > \r\n> >  ##\r\n> >  # @TPMInfo:\r\n> > diff --git a/qemu-options.hx b/qemu-options.hx\r\n> > index 77859a2..1e93e53 100644\r\n> > --- a/qemu-options.hx\r\n> > +++ b/qemu-options.hx\r\n> > @@ -3121,7 +3121,9 @@ DEF(\"tpmdev\", HAS_ARG, QEMU_OPTION_tpmdev, \\\r\n> >      \"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\\n\"\r\n> >      \"                use path to provide path to a character\r\n> > device; default is /dev/tpm0\\n\"\r\n> >      \"                use cancel-path to provide path to TPM's\r\n> > cancel sysfs entry; if\\n\"\r\n> > -    \"                not provided it will be searched for in\r\n> > /sys/class/misc/tpm?/device\\n\",\r\n> > +    \"                not provided it will be searched for in\r\n> > /sys/class/misc/tpm?/device\\n\"\r\n> > +    \"-tpmdev emulator,id=id,chardev=dev\\n\"\r\n> > +    \"                configure the TPM device using chardev\r\n> > backend\\n\",\r\n> >      QEMU_ARCH_ALL)\r\n> >  STEXI\r\n> > \r\n> > @@ -3130,8 +3132,8 @@ The general form of a TPM device option is:\r\n> > \r\n> >  @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]\r\n> >  @findex -tpmdev\r\n> > -Backend type must be:\r\n> > -@option{passthrough}.\r\n> > +Backend type must be either one of the following:\r\n> > +@option{passthrough}, @option{emulator}.\r\n> > \r\n> >  The specific backend type will determine the applicable options.\r\n> >  The @code{-tpmdev} option creates the TPM backend and requires a\r\n> > @@ -3181,6 +3183,20 @@ To create a passthrough TPM use the\r\n> > following two options:\r\n> >  Note that the @code{-tpmdev} id is @code{tpm0} and is referenced\r\n> > by\r\n> >  @code{tpmdev=tpm0} in the device option.\r\n> > \r\n> > +@item -tpmdev emulator, id=@var{id}, chardev=@var{dev}\r\n> > +\r\n> > +(Linux-host only) Enable access to a TPM emulator using Unix\r\n> > domain socket based\r\n> > +chardev backend.\r\n> > +\r\n> > +@option{chardev} specifies the unique ID of a character device\r\n> > backend that provides connection to the software TPM server.\r\n> > +\r\n> > +To create a TPM emulator backend device with chardev socket\r\n> > backend:\r\n> > +@example\r\n> > +\r\n> > +-chardev socket,id=chrtpm,path=/tmp/swtpm-ctrl -tpmdev\r\n> > emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0\r\n> > +\r\n> > +@end example\r\n> > +\r\n> >  @end table\r\n> > \r\n> >  ETEXI\r\n> > --\r\n> > 2.7.4\r\n> > \r\n> \r\n> \r\n- Amarnath","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":"ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y1fmz5gKDz9s7F\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 26 Sep 2017 22:06:11 +1000 (AEST)","from localhost ([::1]:47282 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dwocr-0007Zr-0T\n\tfor incoming@patchwork.ozlabs.org; Tue, 26 Sep 2017 08:06:09 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:50847)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <amarnath.valluri@intel.com>) id 1dwocI-0007Wa-Lb\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 08:05:48 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <amarnath.valluri@intel.com>) id 1dwoc5-0006Jv-83\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 08:05:34 -0400","from mga14.intel.com ([192.55.52.115]:38662)\n\tby eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <amarnath.valluri@intel.com>)\n\tid 1dwoc4-0006Bk-KF\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 08:05:21 -0400","from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t26 Sep 2017 05:05:15 -0700","from irsmsx101.ger.corp.intel.com ([163.33.3.153])\n\tby fmsmga002.fm.intel.com with ESMTP; 26 Sep 2017 05:05:12 -0700","from irsmsx110.ger.corp.intel.com ([169.254.15.8]) by\n\tIRSMSX101.ger.corp.intel.com ([169.254.1.22]) with mapi id\n\t14.03.0319.002; Tue, 26 Sep 2017 13:05:12 +0100"],"X-ExtLoop1":"1","X-IronPort-AV":"E=Sophos; i=\"5.42,440,1500966000\"; d=\"scan'208\";\n\ta=\"1223868209\"","From":"\"Valluri, Amarnath\" <amarnath.valluri@intel.com>","To":"\"marcandre.lureau@gmail.com\" <marcandre.lureau@gmail.com>","Thread-Topic":"[Qemu-devel][PATCH v7 8/8] tpm: Added support for TPM emulator","Thread-Index":"AQHTM576djiiRLAX70GsKUQXwgH+3KLEVJYAgAKzNQA=","Date":"Tue, 26 Sep 2017 12:05:11 +0000","Message-ID":"<1506427596.5843.104.camel@intel.com>","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>\n\t<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>","In-Reply-To":"<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>","Accept-Language":"en-US","Content-Language":"en-US","X-MS-Has-Attach":"","X-MS-TNEF-Correlator":"","x-originating-ip":"[10.237.68.147]","Content-Type":"text/plain; charset=\"utf-8\"","Content-ID":"<91142FD404AD31479F8792964514F885@intel.com>","Content-Transfer-Encoding":"base64","MIME-Version":"1.0","X-detected-operating-system":"by eggs.gnu.org: Genre and OS details not\n\trecognized.","X-Received-From":"192.55.52.115","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"\"qemu-devel@nongnu.org\" <qemu-devel@nongnu.org>,\n\t\"armbru@redhat.com\" <armbru@redhat.com>,\n\t\"dgilbert@redhat.com\" <dgilbert@redhat.com>,\n\t\"stefanb@linux.vnet.ibm.com\" <stefanb@linux.vnet.ibm.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}},{"id":1775423,"web_url":"http://patchwork.ozlabs.org/comment/1775423/","msgid":"<CAJ+F1CK_XRQG3W5A7tST5R1criUO3piohvMXNGyM348fTD7BhQ@mail.gmail.com>","list_archive_url":null,"date":"2017-09-26T12:24:46","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":6442,"url":"http://patchwork.ozlabs.org/api/people/6442/","name":"Marc-André Lureau","email":"marcandre.lureau@gmail.com"},"content":"Hi\n\nOn Tue, Sep 26, 2017 at 2:05 PM, Valluri, Amarnath\n<amarnath.valluri@intel.com> wrote:\n> Hi Marc,\n>\n> Thanks for your time reviewing this patchset. Please find my inline\n> comments.\n>\n> On Sun, 2017-09-24 at 20:52 +0200, Marc-André Lureau wrote:\n>> Hi\n>>\n>> Thanks for the nice update, removing the exec() code, using chardev\n>> and a private socketpair. Some comments below:\n>>\n>> On Fri, Sep 22, 2017 at 2:33 PM, Amarnath Valluri\n>> <amarnath.valluri@intel.com> wrote:\n>> >\n>> > This change introduces a new TPM backend driver that can\n>> > communicate with\n>> > swtpm(software TPM emulator) using unix domain socket interface.\n>> > QEMU talks to\n>> > TPM emulator using socket based chardev backend device.\n>> >\n>> > Swtpm uses two Unix sockets for communications, one for plain TPM\n>> > commands and\n>> > responses, and one for out-of-band control messages. QEMU passes\n>> > data socket\n>> > been used over the control channel.\n>> >\n>> > The swtpm and associated tools can be found here:\n>> >     https://github.com/stefanberger/swtpm\n>> >\n>> > The swtpm's control channel protocol specification can be found\n>> > here:\n>> >     https://github.com/stefanberger/swtpm/wiki/Control-Channel-Spec\n>> > ification\n>> >\n>> > Usage:\n>> >     # setup TPM state directory\n>> >     mkdir /tmp/mytpm\n>> >     chown -R tss:root /tmp/mytpm\n>> >     /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek\n>> >\n>> >     # Ask qemu to use TPM emulator with given tpm state directory\n>> >     qemu-system-x86_64 \\\n>> >         [...] \\\n>> >         -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \\\n>> >         -tpmdev emulator,id=tpm0,chardev=chrtpm \\\n>> >         -device tpm-tis,tpmdev=tpm0 \\\n>> >         [...]\n>> >\n>> > Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>\n>> > ---\n>> >  configure             |  15 +-\n>> >  hmp.c                 |   5 +\n>> >  hw/tpm/Makefile.objs  |   1 +\n>> >  hw/tpm/tpm_emulator.c | 649\n>> > ++++++++++++++++++++++++++++++++++++++++++++++++++\n>> >  hw/tpm/tpm_ioctl.h    | 246 +++++++++++++++++++\n>> >  qapi/tpm.json         |  21 +-\n>> >  qemu-options.hx       |  22 +-\n>> >  7 files changed, 950 insertions(+), 9 deletions(-)\n>> >  create mode 100644 hw/tpm/tpm_emulator.c\n>> >  create mode 100644 hw/tpm/tpm_ioctl.h\n>> >\n>> > diff --git a/configure b/configure\n>> > index cb0f7ed..ce2df2d 100755\n>> > --- a/configure\n>> > +++ b/configure\n>> > @@ -3461,10 +3461,15 @@ fi\n>> >  ##########################################\n>> >  # TPM passthrough is only on x86 Linux\n>> >\n>> > -if test \"$targetos\" = Linux && test \"$cpu\" = i386 -o \"$cpu\" =\n>> > x86_64; then\n>> > -  tpm_passthrough=$tpm\n>> > +if test \"$targetos\" = Linux; then\n>> > +  tpm_emulator=$tpm\n>> > +  if test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\n>> > +    tpm_passthrough=$tpm\n>> > +  else\n>> > +    tpm_passthrough=no\n>> > +  fi\n>> >  else\n>> > -  tpm_passthrough=no\n>> > +  tpm_emulator=no\n>> >  fi\n>> >\n>> >  ##########################################\n>> > @@ -5359,6 +5364,7 @@ echo \"gcov enabled      $gcov\"\n>> >  echo \"TPM support       $tpm\"\n>> >  echo \"libssh2 support   $libssh2\"\n>> >  echo \"TPM passthrough   $tpm_passthrough\"\n>> > +echo \"TPM emulator      $tpm_emulator\"\n>> >  echo \"QOM debugging     $qom_cast_debug\"\n>> >  echo \"Live block migration $live_block_migration\"\n>> >  echo \"lzo support       $lzo\"\n>> > @@ -5943,6 +5949,9 @@ if test \"$tpm\" = \"yes\"; then\n>> >    if test \"$tpm_passthrough\" = \"yes\"; then\n>> >      echo \"CONFIG_TPM_PASSTHROUGH=y\" >> $config_host_mak\n>> >    fi\n>> > +  if test \"$tpm_emulator\" = \"yes\"; then\n>> > +    echo \"CONFIG_TPM_EMULATOR=y\" >> $config_host_mak\n>> It shouldn't require Linux, but posix (and I assume a port to other\n>> systems isn't impossible). same for build-sys / help / comments.\n> I agree, Can you suggest, what is the Qemu way of limiting this to\n> 'posix'.\n>>\n\nthere is CONFIG_POSIX\n\n>> >\n>> > +  fi\n>> >  fi\n>> >\n>> >  echo \"TRACE_BACKENDS=$trace_backends\" >> $config_host_mak\n>> > diff --git a/hmp.c b/hmp.c\n>> > index cf62b2e..7e69eca 100644\n>> > --- a/hmp.c\n>> > +++ b/hmp.c\n>> > @@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict\n>> > *qdict)\n>> >      Error *err = NULL;\n>> >      unsigned int c = 0;\n>> >      TPMPassthroughOptions *tpo;\n>> > +    TPMEmulatorOptions *teo;\n>> >\n>> >      info_list = qmp_query_tpm(&err);\n>> >      if (err) {\n>> > @@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const QDict\n>> > *qdict)\n>> >                             tpo->has_cancel_path ? \",cancel-path=\"\n>> > : \"\",\n>> >                             tpo->has_cancel_path ? tpo->cancel_path\n>> > : \"\");\n>> >              break;\n>> > +        case TPM_TYPE_EMULATOR:\n>> > +            teo = ti->options->u.emulator.data;\n>> > +            monitor_printf(mon, \",chardev=%s\", teo->chardev);\n>> > +            break;\n>> >          case TPM_TYPE__MAX:\n>> >              break;\n>> >          }\n>> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs\n>> > index 64cecc3..41f0b7a 100644\n>> > --- a/hw/tpm/Makefile.objs\n>> > +++ b/hw/tpm/Makefile.objs\n>> > @@ -1,2 +1,3 @@\n>> >  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o\n>> >  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o\n>> > tpm_util.o\n>> > +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o\n>> > diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c\n>> > new file mode 100644\n>> > index 0000000..c02bbe2\n>> > --- /dev/null\n>> > +++ b/hw/tpm/tpm_emulator.c\n>> > @@ -0,0 +1,649 @@\n>> > +/*\n>> > + *  emulator TPM driver\n>> > + *\n>> > + *  Copyright (c) 2017 Intel Corporation\n>> > + *  Author: Amarnath Valluri <amarnath.valluri@intel.com>\n>> > + *\n>> > + *  Copyright (c) 2010 - 2013 IBM Corporation\n>> > + *  Authors:\n>> > + *    Stefan Berger <stefanb@us.ibm.com>\n>> > + *\n>> > + *  Copyright (C) 2011 IAIK, Graz University of Technology\n>> > + *    Author: Andreas Niederl\n>> > + *\n>> > + * This library is free software; you can redistribute it and/or\n>> > + * modify it under the terms of the GNU Lesser General Public\n>> > + * License as published by the Free Software Foundation; either\n>> > + * version 2 of the License, or (at your option) any later\n>> > version.\n>> > + *\n>> > + * This library is distributed in the hope that it will be useful,\n>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of\n>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n>> > GNU\n>> > + * Lesser General Public License for more details.\n>> > + *\n>> > + * You should have received a copy of the GNU Lesser General\n>> > Public\n>> > + * License along with this library; if not, see <http://www.gnu.or\n>> > g/licenses/>\n>> > + *\n>> > + */\n>> > +\n>> > +#include \"qemu/osdep.h\"\n>> > +#include \"qemu/error-report.h\"\n>> > +#include \"qemu/sockets.h\"\n>> > +#include \"io/channel-socket.h\"\n>> > +#include \"sysemu/tpm_backend.h\"\n>> > +#include \"tpm_int.h\"\n>> > +#include \"hw/hw.h\"\n>> > +#include \"hw/i386/pc.h\"\n>> > +#include \"tpm_util.h\"\n>> > +#include \"tpm_ioctl.h\"\n>> > +#include \"migration/blocker.h\"\n>> > +#include \"qapi/error.h\"\n>> > +#include \"chardev/char-fe.h\"\n>> > +\n>> > +#include <fcntl.h>\n>> > +#include <sys/types.h>\n>> > +#include <sys/stat.h>\n>> > +#include <stdio.h>\n>> > +\n>> > +#define DEBUG_TPM 0\n>> > +\n>> > +#define DPRINT(fmt, ...) do { \\\n>> > +    if (DEBUG_TPM) { \\\n>> > +        fprintf(stderr, fmt, ## __VA_ARGS__); \\\n>> > +    } \\\n>> > +} while (0);\n>> > +\n>> > +#define DPRINTF(fmt, ...) DPRINT(\"tpm-emulator: \"fmt\"\\n\",\n>> > __VA_ARGS__)\n>> I would define a single DPRINTF() (& drop DPRINT usage below)\n> Ok, will do\n>>\n>>\n>> >\n>> > +\n>> > +#define TYPE_TPM_EMULATOR \"tpm-emulator\"\n>> > +#define TPM_EMULATOR(obj) \\\n>> > +    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)\n>> > +\n>> > +#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps &\n>> > (cap)) == (cap))\n>> > +\n>> > +static const TPMDriverOps tpm_emulator_driver;\n>> > +\n>> > +/* data structures */\n>> > +typedef struct TPMEmulator {\n>> > +    TPMBackend parent;\n>> > +\n>> > +    TPMEmulatorOptions *options;\n>> Contrary to my comment on previous patch, I realize it is convenient\n>> to have a qapi pointer here, so you can use the free visitor later.\n>>\n>> >\n>> > +    CharBackend ctrl_dev;\n>> ctrl_chr perhaps? or just chr or be (the most common name in other\n>> devices).\n>>\n>> >\n>> > +    QIOChannel *data_ioc;\n>> > +    bool op_executing;\n>> > +    bool op_canceled;\n>> I think those 2 fields can be dropped, see below.\n>>\n>> >\n>> > +    bool had_startup_error;\n>> I think some little refactoring could remove the whole\n>> had_startup_error() backend & callback before or after the series.\n>> tpm_backend_startup_tpm() already returns an error code.  device or\n>> common backend code could handle & remember that.\n> Yes, i agree, we can avoid had_startup_error() from DriverOps, i will\n> do this.\n>>\n>> >\n>> > +    TPMVersion tpm_version;\n>> This is probably worth to consider in common code instead, but let's\n>> not worry about it.\n>>\n>> >\n>> > +    ptm_cap caps; /* capabilities of the TPM */\n>> > +    uint8_t cur_locty_number; /* last set locality */\n>> > +    QemuMutex state_lock;\n>> > +    Error *migration_blocker;\n>> > +} TPMEmulator;\n>> > +\n>> > +\n>> > +static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long\n>> > cmd, void *msg,\n>> > +                                size_t msg_len_in, size_t\n>> > msg_len_out)\n>> > +{\n>> > +    uint32_t cmd_no = cpu_to_be32(cmd);\n>> > +    ssize_t n = sizeof(uint32_t) + msg_len_in;\n>> > +    uint8_t *buf = NULL;\n>> > +\n>> > +    buf = (uint8_t *)malloc(n);\n>> could be g_alloca() instead. Alternatively, why not call 2 write()\n>> instead?\n>>\n>> none of the casts in this function are necessary, please remove them.\n> Ok, will change to aclloca()\n\nI just realized this is SOCK_SEQPACKET, ok\n\n>>\n>> >\n>> > +    memcpy(buf, &cmd_no, sizeof(cmd_no));\n>> > +    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);\n>> > +\n>> > +    n += qemu_chr_fe_write_all(dev, (const uint8_t *)buf, n);\n>> weird\n>>\n>> >\n>> > +    free(buf);\n>> > +\n>> > +    if (n > 0) {\n>> with the n += above, you'll get interesting behaviour :)\n> Ya, it was typo :)\n>>\n>> You probably want to check if any write above failed, and return\n>> early\n>> for the error case.\n>>\n>> Please improve the error handling in this function\n>>\n>> >\n>> > +        if (msg_len_out > 0) {\n>> > +            n = qemu_chr_fe_read_all(dev, (uint8_t *)msg,\n>> > msg_len_out);\n>> > +            /* simulate ioctl return value */\n>> > +            if (n > 0) {\n>> > +                n = 0;\n>> > +            }\n>> > +        } else {\n>> > +            n = 0;\n>> > +        }\n>> > +    }\n>> > +    return n;\n>> > +}\n>> > +\n>> > +static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,\n>> tpm_pt was tpm_passthrough I suppose.\n>>\n>> Please rename tpm_pt tpm_emu (or I would suggest \"self\", but this\n>> isn't common name in qemu code - it's actually common in a close\n>> c-object world., and it is quite convenient...)\n> My interpretation about _pt was 'pointer' ;-) i will consider your\n> suggetion.\n>>\n>> >\n>> > +                                     const uint8_t *in, uint32_t\n>> > in_len,\n>> > +                                     uint8_t *out, uint32_t\n>> > out_len,\n>> > +                                     bool *selftest_done)\n>> > +{\n>> > +    ssize_t ret;\n>> > +    bool is_selftest = false;\n>> > +    const struct tpm_resp_hdr *hdr = NULL;\n>> > +    Error *err = NULL;\n>> > +\n>> > +    tpm_pt->op_canceled = false;\n>> > +    tpm_pt->op_executing = true;\n>> > +    if (selftest_done) {\n>> > +        *selftest_done = false;\n>> > +        is_selftest = tpm_util_is_selftest(in, in_len);\n>> > +    }\n>> > +\n>> > +    ret = qio_channel_write(tpm_pt->data_ioc, (char *)in, in_len,\n>> > &err);\n>> hmm, too bad qio_channel_write() doesn't take a void *\n>>\n>> why not write_all()?\n> Agreed\n>>\n>> >\n>> > +    if (ret != in_len || err) {\n>> > +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n>> I don't think ECANCELED make sense for emulator code.\n>>\n>> >\n>> > +            error_report(\"tpm-emulator: error while transmitting\n>> > data \"\n>> > +                         \"to TPM: %s\", err ? error_get_pretty(err)\n>> > : \"\");\n>> > +            error_free(err);\n>> > +        }\n>> > +        goto err_exit;\n>> > +    }\n>> > +\n>> > +    tpm_pt->op_executing = false;\n>> > +\n>> > +    ret = qio_channel_read(tpm_pt->data_ioc, (char *)out, out_len,\n>> > &err);\n>> > +    if (ret < 0 || err) {\n>> read_all() ?\n> The issue with read_all() is it does not return the no of bytes it\n> read, so i would like to stict to _read()\n\nok\n\n>>\n>> >\n>> > +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\n>> > +            error_report(\"tpm-emulator: error while reading data\n>> > from \"\n>> > +                         \"TPM: %s\", err ? error_get_pretty(err) :\n>> > \"\");\n>> > +            error_free(err);\n>> > +        }\n>> > +    } else if (ret >= sizeof(*hdr)) {\n>> > +        hdr = (struct tpm_resp_hdr *)out;\n>> > +    }\n>> > +\n>> > +    if (!hdr || be32_to_cpu(hdr->len) != ret) {\n>> > +        error_report(\"tpm-emulator: received invalid response \"\n>> > +                     \"packet from TPM with length :%ld\", ret);\n>> > +        ret = -1;\n>> > +        goto err_exit;\n>> > +    }\n>> > +\n>> > +    if (is_selftest) {\n>> > +        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);\n>> > +    }\n>> > +\n>> > +    return 0;\n>> > +\n>> > +err_exit:\n>> > +    if (ret < 0) {\n>> > +        tpm_util_write_fatal_error_response(out, out_len);\n>> > +    }\n>> > +\n>> > +    tpm_pt->op_executing = false;\n>> > +\n>> > +    return ret;\n>> > +}\n>> > +\n>> > +static int tpm_emulator_set_locality(TPMEmulator *tpm_pt, uint8_t\n>> > locty_number)\n>> > +{\n>> > +    ptm_loc loc;\n>> > +\n>> > +    DPRINTF(\"%s : locality: 0x%x\", __func__, locty_number);\n>> > +\n>> > +    if (tpm_pt->cur_locty_number != locty_number) {\n>> return early instead if ==, to avoid code indent etc\n> Ok\n>>\n>> >\n>> > +        DPRINTF(\"setting locality : 0x%x\", locty_number);\n>> > +        loc.u.req.loc = locty_number;\n>> This number isn't set in be like the rest of the protocol?\n> I doubt if i get ur point :(, can you please elaborate.\n\nIn the rest of the protocol, it uses big-endian. I suppose you should\ncpu_to_be32(locty_number).\n\n>>\n>> >\n>> > +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\n>> > CMD_SET_LOCALITY, &loc,\n>> > +                             sizeof(loc), sizeof(loc)) < 0) {\n>> > +            error_report(\"tpm-emulator: could not set locality :\n>> > %s\",\n>> > +                         strerror(errno));\n>> > +            return -1;\n>> > +        }\n>> > +        loc.u.resp.tpm_result =\n>> > be32_to_cpu(loc.u.resp.tpm_result);\n>> > +        if (loc.u.resp.tpm_result != 0) {\n>> > +            error_report(\"tpm-emulator: TPM result for set\n>> > locality : 0x%x\",\n>> > +                         loc.u.resp.tpm_result);\n>> > +            return -1;\n>> > +        }\n>> > +        tpm_pt->cur_locty_number = locty_number;\n>> > +    }\n>> > +    return 0;\n>> > +}\n>> > +\n>> > +static void tpm_emulator_handle_request(TPMBackend *tb,\n>> > TPMBackendCmd cmd)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +    TPMLocality *locty = NULL;\n>> > +    bool selftest_done = false;\n>> > +\n>> > +    DPRINTF(\"processing command type %d\", cmd);\n>> > +\n>> > +    switch (cmd) {\n>> > +    case TPM_BACKEND_CMD_PROCESS_CMD:\n>> > +        qemu_mutex_lock(&tpm_pt->state_lock);\n>> > +        locty = tb->tpm_state->locty_data;\n>> > +        if (tpm_emulator_set_locality(tpm_pt,\n>> > +                                      tb->tpm_state->locty_number)\n>> > < 0) {\n>> > +            tpm_util_write_fatal_error_response(locty-\n>> > >r_buffer.buffer,\n>> > +                                           locty->r_buffer.size);\n>> return / goto here instead of else.\n> We should not retrun from here, we have to propagte the error response\n> to device, and unlock the state.\n>>\n>> >\n>> > +        } else {\n>> > +            tpm_emulator_unix_tx_bufs(tpm_pt, locty-\n>> > >w_buffer.buffer,\n>> > +                                              locty->w_offset,\n>> > +                                              locty-\n>> > >r_buffer.buffer,\n>> > +                                              locty-\n>> > >r_buffer.size,\n>> > +                                              &selftest_done);\n>> no error handling?\n> The error case is supposed to handle by device, where we are filling\n> into out buffer, using tpm_util_write_fatal_error_response().\n>>\n>> >\n>> > +        }\n>> > +\n>> > +        tb->recv_data_callback(tb->tpm_state, tb->tpm_state-\n>> > >locty_number,\n>> > +                               selftest_done);\n>> > +        qemu_mutex_unlock(&tpm_pt->state_lock);\n>> > +\n>> > +        break;\n>> > +    case TPM_BACKEND_CMD_INIT:\n>> > +    case TPM_BACKEND_CMD_END:\n>> > +    case TPM_BACKEND_CMD_TPM_RESET:\n>> > +        /* nothing to do */\n>> > +        break;\n>> > +    }\n>> > +}\n>> > +\n>> > +/*\n>> > + * Gracefully shut down the external unixio TPM\n>> > + */\n>> > +static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)\n>> > +{\n>> > +    ptm_res res;\n>> > +\n>> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SHUTDOWN,\n>> > &res, 0,\n>> > +                         sizeof(res)) < 0) {\n>> > +        error_report(\"tpm-emulator: Could not cleanly shutdown the\n>> > TPM: %s\",\n>> > +                     strerror(errno));\n>> > +    } else if (res != 0) {\n>> > +        error_report(\"tpm-emulator: TPM result for sutdown: 0x%x\",\n>> > +                     be32_to_cpu(res));\n>> > +    }\n>> > +}\n>> > +\n>> > +static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)\n>> > +{\n>> > +    DPRINTF(\"%s\", __func__);\n>> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\n>> > CMD_GET_CAPABILITY,\n>> > +                         &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) <\n>> > 0) {\n>> > +        error_report(\"tpm-emulator: probing failed : %s\",\n>> > strerror(errno));\n>> > +        return -1;\n>> > +    }\n>> > +\n>> > +    tpm_pt->caps = be64_to_cpu(tpm_pt->caps);\n>> > +\n>> > +    DPRINTF(\"capbilities : 0x%lx\", tpm_pt->caps);\n>> > +\n>> > +    return 0;\n>> > +}\n>> > +\n>> > +static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)\n>> > +{\n>> > +    ptm_cap caps = 0;\n>> > +    const char *tpm = NULL;\n>> > +\n>> > +    /* check for min. required capabilities */\n>> > +    switch (tpm_pt->tpm_version) {\n>> > +    case TPM_VERSION_1_2:\n>> > +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |\n>> > PTM_CAP_GET_TPMESTABLISHED |\n>> > +               PTM_CAP_SET_LOCALITY;\n>> > +        tpm = \"1.2\";\n>> > +        break;\n>> > +    case TPM_VERSION_2_0:\n>> > +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |\n>> > PTM_CAP_GET_TPMESTABLISHED |\n>> > +               PTM_CAP_SET_LOCALITY |\n>> > PTM_CAP_RESET_TPMESTABLISHED;\n>> > +        tpm = \"2\";\n>> > +        break;\n>> > +    case TPM_VERSION_UNSPEC:\n>> > +        error_report(\"tpm-emulator: TPM version has not been\n>> > set\");\n>> > +        return -1;\n>> > +    }\n>> > +\n>> > +    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {\n>> > +        error_report(\"tpm-emulator: TPM does not implement minimum\n>> > set of \"\n>> > +                     \"required capabilities for TPM %s (0x%x)\",\n>> > tpm, (int)caps);\n>> > +        return -1;\n>> > +    }\n>> > +\n>> > +    return 0;\n>> > +}\n>> > +\n>> > +static int tpm_emulator_startup_tpm(TPMBackend *tb)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +    ptm_init init;\n>> > +    ptm_res res;\n>> > +\n>> > +    DPRINTF(\"%s\", __func__);\n>> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_INIT, &init,\n>> > sizeof(init),\n>> > +                         sizeof(init)) < 0) {\n>> > +        error_report(\"tpm-emulator: could not send INIT: %s\",\n>> > +                     strerror(errno));\n>> > +        goto err_exit;\n>> > +    }\n>> > +\n>> > +    res = be32_to_cpu(init.u.resp.tpm_result);\n>> > +    if (res) {\n>> > +        error_report(\"tpm-emulator: TPM result for CMD_INIT:\n>> > 0x%x\", res);\n>> > +        goto err_exit;\n>> > +    }\n>> > +    return 0;\n>> > +\n>> > +err_exit:\n>> > +    tpm_pt->had_startup_error = true;\n>> > +    return -1;\n>> > +}\n>> > +\n>> > +static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +    ptm_est est;\n>> > +\n>> > +    DPRINTF(\"%s\", __func__);\n>> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\n>> > CMD_GET_TPMESTABLISHED, &est, 0,\n>> > +                         sizeof(est)) < 0) {\n>> > +        error_report(\"tpm-emulator: Could not get the TPM\n>> > established flag: %s\",\n>> > +                     strerror(errno));\n>> > +        return false;\n>> > +    }\n>> > +    DPRINTF(\"established flag: %0x\", est.u.resp.bit);\n>> > +\n>> > +    return (est.u.resp.bit != 0);\n>> > +}\n>> > +\n>> > +static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,\n>> > +                                                   uint8_t locty)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +    ptm_reset_est reset_est;\n>> > +    ptm_res res;\n>> > +\n>> > +    /* only a TPM 2.0 will support this */\n>> > +    if (tpm_pt->tpm_version == TPM_VERSION_2_0) {\n>> > +        reset_est.u.req.loc = tpm_pt->cur_locty_number;\n>> > +\n>> > +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\n>> > CMD_RESET_TPMESTABLISHED,\n>> > +                                 &reset_est, sizeof(reset_est),\n>> > +                                 sizeof(reset_est)) < 0) {\n>> > +            error_report(\"tpm-emulator: Could not reset the\n>> > establishment bit: \"\n>> > +                          \"%s\", strerror(errno));\n>> > +            return -1;\n>> > +        }\n>> > +\n>> > +        res = be32_to_cpu(reset_est.u.resp.tpm_result);\n>> > +        if (res) {\n>> > +            error_report(\"tpm-emulator: TPM result for rest\n>> > establixhed flag: \"\n>> > +                         \"0x%x\", res);\n>> > +            return -1;\n>> > +        }\n>> > +    }\n>> > +\n>> > +    return 0;\n>> > +}\n>> > +\n>> > +static bool tpm_emulator_had_startup_error(TPMBackend *tb)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +\n>> > +    return tpm_pt->had_startup_error;\n>> > +}\n>> > +\n>> > +static void tpm_emulator_cancel_cmd(TPMBackend *tb)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +    ptm_res res;\n>> > +\n>> > +    /*\n>> > +     * As of Linux 3.7 the tpm_tis driver does not properly cancel\n>> > +     * commands on all TPM manufacturers' TPMs.\n>> > +     * Only cancel if we're busy so we don't cancel someone else's\n>> > +     * command, e.g., a command executed on the host.\n>> > +     */\n>> > +    if (tpm_pt->op_executing) {\n>> The field is set in the worker thread. This is racy. Fortunately this\n>> is not relevant for emulator, I think you can simply drop that check\n>> and the variable. Stefan should confirm though.\n>>\n>> >\n>> > +        if (TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt,\n>> > PTM_CAP_CANCEL_TPM_CMD)) {\n>> > +            if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\n>> > CMD_CANCEL_TPM_CMD,\n>> > +                                     &res, 0, sizeof(res)) < 0) {\n>> > +                error_report(\"tpm-emulator: Could not cancel\n>> > command: %s\",\n>> > +                             strerror(errno));\n>> > +            } else if (res != 0) {\n>> > +                error_report(\"tpm-emulator: Failed to cancel TPM:\n>> > 0x%x\",\n>> > +                             be32_to_cpu(res));\n>> > +            } else {\n>> > +                tpm_pt->op_canceled = true;\n>> > +            }\n>> > +        }\n>> > +    }\n>> > +}\n>> > +\n>> > +static void tpm_emulator_reset(TPMBackend *tb)\n>> > +{\n>> > +    DPRINTF(\"%s\", __func__);\n>> > +\n>> > +    tpm_emulator_cancel_cmd(tb);\n>> > +}\n>> > +\n>> > +static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +\n>> > +    return tpm_pt->tpm_version;\n>> > +}\n>> > +\n>> > +static void tpm_emulator_block_migration(TPMEmulator *tpm_pt)\n>> > +{\n>> > +    Error *err = NULL;\n>> > +\n>> > +    error_setg(&tpm_pt->migration_blocker,\n>> > +               \"Migration disabled: TPM emulator not yet\n>> > migratable\");\n>> > +    migrate_add_blocker(tpm_pt->migration_blocker, &err);\n>> > +    if (err) {\n>> > +        error_free(err);\n>> probably better to report_err it instead\n> Ok\n>>\n>> >\n>> > +        error_free(tpm_pt->migration_blocker);\n>> > +        tpm_pt->migration_blocker = NULL;\n>> and return an error code.\n> Will do\n>>\n>> >\n>> > +    }\n>> > +}\n>> > +\n>> > +static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_pt)\n>> > +{\n>> > +    ptm_res res;\n>> > +    Error *err = NULL;\n>> > +    int fds[2] = { -1, -1 };\n>> > +\n>> > +    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {\n>> > +        error_report(\"tpm-emulator: Failed to create socketpair\");\n>> > +        return -1;\n>> > +    }\n>> > +\n>> > +    qemu_chr_fe_set_msgfds(&tpm_pt->ctrl_dev, fds + 1, 1);\n>> > +\n>> > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SET_DATAFD,\n>> > &res, 0,\n>> > +                    sizeof(res)) || res != 0) {\n>> Yay! for making life easier and hiding a protocol detail.\n>>\n>> >\n>> > +        error_report(\"tpm-emulator: Failed to send CMD_SET_DATAFD:\n>> > %s\",\n>> > +                     strerror(errno));\n>> > +        goto err_exit;\n>> > +    }\n>> > +\n>> > +    tpm_pt->data_ioc =\n>> > QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));\n>> > +    if (err) {\n>> > +        error_report(\"tpm-emulator: Failed to create io channel :\n>> > %s\",\n>> > +                       error_get_pretty(err));\n>> error_prepend()?\n> Ok\n>>\n>> >\n>> > +        error_free(err);\n>> > +        goto err_exit;\n>> > +    }\n>> close fds[1] ?\n> I guess we are not supposed to close the other end of the\n> socketpair/pipe, as it is not forked process.\n\nYou will close this end, not the other end.\n\n>>\n>> >\n>> > +\n>> > +    return 0;\n>> > +\n>> > +err_exit:\n>> > +    closesocket(fds[0]);\n>> > +    closesocket(fds[1]);\n>> > +    return -1;\n>> > +}\n>> > +\n>> > +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt,\n>> > QemuOpts *opts)\n>> > +{\n>> > +    const char *value;\n>> > +\n>> > +    value = qemu_opt_get(opts, \"chardev\");\n>> > +    if (value) {\n>> > +        Error *err = NULL;\n>> > +        Chardev *dev = qemu_chr_find(value);\n>> > +\n>> > +        tpm_pt->options->chardev = g_strdup(value);\n>> > +\n>> > +        if (!dev || !qemu_chr_fe_init(&tpm_pt->ctrl_dev, dev,\n>> > &err)) {\n>> > +            error_report(\"tpm-emulator: No valid chardev found at\n>> > '%s': %s\",\n>> > +                         value, err ? error_get_pretty(err) : \"\");\n>> > +            error_free(err);\n>> error_prepend\n> Ok\n>>\n>> >\n>> > +            goto err;\n>> > +        }\n>> > +    }\n>> > +\n>> > +    if (tpm_emulator_prepare_data_fd(tpm_pt) < 0) {\n>> > +        goto err;\n>> > +    }\n>> > +\n>> > +    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as\n>> > it also used\n>> > +     * by passthrough driver, which not yet using GIOChannel.\n>> > +     */\n>> > +    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_pt->data_ioc)-\n>> > >fd,\n>> > +                             &tpm_pt->tpm_version)) {\n>> > +        error_report(\"'%s' is not emulating TPM device. Error:\n>> > %s\",\n>> > +                      tpm_pt->options->chardev, strerror(errno));\n>> > +        goto err;\n>> > +    }\n>> > +\n>> > +    DPRINTF(\"TPM Version %s\", tpm_pt->tpm_version ==\n>> > TPM_VERSION_1_2 ? \"1.2\" :\n>> > +             (tpm_pt->tpm_version == TPM_VERSION_2_0 ?  \"2.0\" :\n>> > \"Unspecified\"));\n>> > +\n>> > +    if (tpm_emulator_probe_caps(tpm_pt) ||\n>> > +        tpm_emulator_check_caps(tpm_pt)) {\n>> > +        goto err;\n>> > +    }\n>> > +\n>> > +    tpm_emulator_block_migration(tpm_pt);\n>> > +\n>> > +    return 0;\n>> > +\n>> > +err:\n>> > +    DPRINT(\"Startup error\\n\");\n>> > +    return -1;\n>> > +}\n>> > +\n>> > +static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char\n>> > *id)\n>> > +{\n>> > +    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));\n>> > +\n>> > +    tb->id = g_strdup(id);\n>> > +\n>> > +    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {\n>> > +        goto err_exit;\n>> > +    }\n>> > +\n>> > +    return tb;\n>> > +\n>> > +err_exit:\n>> > +    object_unref(OBJECT(tb));\n>> > +\n>> > +    return NULL;\n>> > +}\n>> > +\n>> > +static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend\n>> > *tb)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\n>> > +    TpmTypeOptions *options = NULL;\n>> > +    TPMEmulatorOptions *eoptions = NULL;\n>> > +\n>> > +    eoptions = g_new0(TPMEmulatorOptions, 1);\n>> > +    if (!eoptions) {\n>> > +        return NULL;\n>> > +    }\n>> > +    DPRINTF(\"%s\", __func__);\n>> > +\n>> > +    eoptions->chardev = g_strdup(tpm_pt->options->chardev);\n>> > +    options = g_new0(TpmTypeOptions, 1);\n>> > +    if (!options) {\n>> > +        qapi_free_TPMEmulatorOptions(eoptions);\n>> > +        return NULL;\n>> > +    }\n>> > +\n>> > +    options->type = TPM_TYPE_EMULATOR;\n>> > +    options->u.emulator.data = eoptions;\n>> I think this is a job for QAPI_CLONE.\n>>\n>> >\n>> > +\n>> > +    return options;\n>> > +}\n>> > +\n>> > +static const QemuOptDesc tpm_emulator_cmdline_opts[] = {\n>> > +    TPM_STANDARD_CMDLINE_OPTS,\n>> > +    {\n>> > +        .name = \"chardev\",\n>> > +        .type = QEMU_OPT_STRING,\n>> > +        .help = \"Character device to use for out-of-band control\n>> > messages\",\n>> > +    },\n>> > +    { /* end of list */ },\n>> > +};\n>> > +\n>> > +static const TPMDriverOps tpm_emulator_driver = {\n>> > +    .type                     = TPM_TYPE_EMULATOR,\n>> > +    .opts                     = tpm_emulator_cmdline_opts,\n>> > +    .desc                     = \"TPM emulator backend driver\",\n>> > +\n>> > +    .create                   = tpm_emulator_create,\n>> > +    .startup_tpm              = tpm_emulator_startup_tpm,\n>> > +    .reset                    = tpm_emulator_reset,\n>> > +    .had_startup_error        = tpm_emulator_had_startup_error,\n>> > +    .cancel_cmd               = tpm_emulator_cancel_cmd,\n>> > +    .get_tpm_established_flag =\n>> > tpm_emulator_get_tpm_established_flag,\n>> > +    .reset_tpm_established_flag =\n>> > tpm_emulator_reset_tpm_established_flag,\n>> > +    .get_tpm_version          = tpm_emulator_get_tpm_version,\n>> > +    .get_tpm_options          = tpm_emulator_get_tpm_options,\n>> > +};\n>> > +\n>> > +static void tpm_emulator_inst_init(Object *obj)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n>> > +\n>> > +    DPRINTF(\"%s\", __func__);\n>> > +    tpm_pt->options = g_new0(TPMEmulatorOptions, 1);\n>> > +    tpm_pt->op_executing = tpm_pt->op_canceled = false;\n>> > +    tpm_pt->had_startup_error = false;\n>> > +    tpm_pt->cur_locty_number = ~0;\n>> > +    qemu_mutex_init(&tpm_pt->state_lock);\n>> > +}\n>> > +\n>> > +static void tpm_emulator_inst_finalize(Object *obj)\n>> > +{\n>> > +    TPMEmulator *tpm_pt = TPM_EMULATOR(obj);\n>> > +\n>> > +    tpm_emulator_cancel_cmd(TPM_BACKEND(obj));\n>> > +    tpm_emulator_shutdown(tpm_pt);\n>> > +\n>> > +    if (tpm_pt->data_ioc) {\n>> > +        qio_channel_close(tpm_pt->data_ioc, NULL);\n>> > +    }\n>> > +\n>> > +    qemu_chr_fe_deinit(&tpm_pt->ctrl_dev, false);\n>> > +\n>> > +    if (tpm_pt->options) {\n>> > +        qapi_free_TPMEmulatorOptions(tpm_pt->options);\n>> > +    }\n>> > +\n>> > +    if (tpm_pt->migration_blocker) {\n>> > +        migrate_del_blocker(tpm_pt->migration_blocker);\n>> > +        error_free(tpm_pt->migration_blocker);\n>> > +    }\n>> > +}\n>> > +\n>> > +static void tpm_emulator_class_init(ObjectClass *klass, void\n>> > *data)\n>> > +{\n>> > +    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);\n>> > +    tbc->ops = &tpm_emulator_driver;\n>> > +    tbc->handle_request = tpm_emulator_handle_request;\n>> > +}\n>> > +\n>> > +static const TypeInfo tpm_emulator_info = {\n>> > +    .name = TYPE_TPM_EMULATOR,\n>> > +    .parent = TYPE_TPM_BACKEND,\n>> > +    .instance_size = sizeof(TPMEmulator),\n>> > +    .class_init = tpm_emulator_class_init,\n>> > +    .instance_init = tpm_emulator_inst_init,\n>> > +    .instance_finalize = tpm_emulator_inst_finalize,\n>> > +};\n>> > +\n>> > +static void tpm_emulator_register(void)\n>> > +{\n>> > +    type_register_static(&tpm_emulator_info);\n>> > +    tpm_register_driver(&tpm_emulator_driver);\n>> > +}\n>> > +\n>> > +type_init(tpm_emulator_register)\n>> > diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h\n>> > new file mode 100644\n>> > index 0000000..33564b1\n>> > --- /dev/null\n>> > +++ b/hw/tpm/tpm_ioctl.h\n>> This file is copied from swtpm project. Could swtpm have it installed\n>> on system instead?\n>>\n>> >\n>> > @@ -0,0 +1,246 @@\n>> > +/*\n>> > + * tpm_ioctl.h\n>> > + *\n>> > + * (c) Copyright IBM Corporation 2014, 2015.\n>> > + *\n>> > + * This file is licensed under the terms of the 3-clause BSD\n>> > license\n>> > + */\n>> > +#ifndef _TPM_IOCTL_H_\n>> > +#define _TPM_IOCTL_H_\n>> > +\n>> > +#include <stdint.h>\n>> > +#include <sys/uio.h>\n>> > +#include <sys/types.h>\n>> > +#include <sys/ioctl.h>\n>> > +\n>> > +/*\n>> > + * Every response from a command involving a TPM command execution\n>> > must hold\n>> > + * the ptm_res as the first element.\n>> > + * ptm_res corresponds to the error code of a command executed by\n>> > the TPM.\n>> > + */\n>> > +\n>> > +typedef uint32_t ptm_res;\n>> > +\n>> > +/* PTM_GET_TPMESTABLISHED: get the establishment bit */\n>> > +struct ptm_est {\n>> > +    union {\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +            unsigned char bit; /* TPM established bit */\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +/* PTM_RESET_TPMESTABLISHED: reset establishment bit */\n>> > +struct ptm_reset_est {\n>> > +    union {\n>> > +        struct {\n>> > +            uint8_t loc; /* locality to use */\n>> > +        } req; /* request */\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +/* PTM_INIT */\n>> > +struct ptm_init {\n>> > +    union {\n>> > +        struct {\n>> > +            uint32_t init_flags; /* see definitions below */\n>> > +        } req; /* request */\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +/* above init_flags */\n>> > +#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)\n>> > +    /* delete volatile state file after reading it */\n>> > +\n>> > +/* PTM_SET_LOCALITY */\n>> > +struct ptm_loc {\n>> > +    union {\n>> > +        struct {\n>> > +            uint8_t loc; /* locality to set */\n>> > +        } req; /* request */\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +/* PTM_HASH_DATA: hash given data */\n>> > +struct ptm_hdata {\n>> > +    union {\n>> > +        struct {\n>> > +            uint32_t length;\n>> > +            uint8_t data[4096];\n>> > +        } req; /* request */\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +/*\n>> > + * size of the TPM state blob to transfer; x86_64 can handle 8k,\n>> > + * ppc64le only ~7k; keep the response below a 4k page size\n>> > + */\n>> > +#define PTM_STATE_BLOB_SIZE (3 * 1024)\n>> > +\n>> > +/*\n>> > + * The following is the data structure to get state blobs from the\n>> > TPM.\n>> > + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE,\n>> > multiple reads\n>> > + * with this ioctl and with adjusted offset are necessary. All\n>> > bytes\n>> > + * must be transferred and the transfer is done once the last byte\n>> > has been\n>> > + * returned.\n>> > + * It is possible to use the read() interface for reading the\n>> > data; however, the\n>> > + * first bytes of the state blob will be part of the response to\n>> > the ioctl(); a\n>> > + * subsequent read() is only necessary if the total length\n>> > (totlength) exceeds\n>> > + * the number of received bytes. seek() is not supported.\n>> > + */\n>> > +struct ptm_getstate {\n>> > +    union {\n>> > +        struct {\n>> > +            uint32_t state_flags; /* may be:\n>> > PTM_STATE_FLAG_DECRYPTED */\n>> > +            uint32_t type;        /* which blob to pull */\n>> > +            uint32_t offset;      /* offset from where to read */\n>> > +        } req; /* request */\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +            uint32_t state_flags; /* may be:\n>> > PTM_STATE_FLAG_ENCRYPTED */\n>> > +            uint32_t totlength;   /* total length that will be\n>> > transferred */\n>> > +            uint32_t length;      /* number of bytes in following\n>> > buffer */\n>> > +            uint8_t  data[PTM_STATE_BLOB_SIZE];\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +/* TPM state blob types */\n>> > +#define PTM_BLOB_TYPE_PERMANENT  1\n>> > +#define PTM_BLOB_TYPE_VOLATILE   2\n>> > +#define PTM_BLOB_TYPE_SAVESTATE  3\n>> > +\n>> > +/* state_flags above : */\n>> > +#define PTM_STATE_FLAG_DECRYPTED     1 /* on input:  get decrypted\n>> > state */\n>> > +#define PTM_STATE_FLAG_ENCRYPTED     2 /* on output: state is\n>> > encrypted */\n>> > +\n>> > +/*\n>> > + * The following is the data structure to set state blobs in the\n>> > TPM.\n>> > + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE,\n>> > multiple\n>> > + * 'writes' using this ioctl are necessary. The last packet is\n>> > indicated\n>> > + * by the length being smaller than the PTM_STATE_BLOB_SIZE.\n>> > + * The very first packet may have a length indicator of '0'\n>> > enabling\n>> > + * a write() with all the bytes from a buffer. If the write()\n>> > interface\n>> > + * is used, a final ioctl with a non-full buffer must be made to\n>> > indicate\n>> > + * that all data were transferred (a write with 0 bytes would not\n>> > work).\n>> > + */\n>> > +struct ptm_setstate {\n>> > +    union {\n>> > +        struct {\n>> > +            uint32_t state_flags; /* may be\n>> > PTM_STATE_FLAG_ENCRYPTED */\n>> > +            uint32_t type;        /* which blob to set */\n>> > +            uint32_t length;      /* length of the data;\n>> > +                                     use 0 on the first packet to\n>> > +                                     transfer using write() */\n>> > +            uint8_t data[PTM_STATE_BLOB_SIZE];\n>> > +        } req; /* request */\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +/*\n>> > + * PTM_GET_CONFIG: Data structure to get runtime configuration\n>> > information\n>> > + * such as which keys are applied.\n>> > + */\n>> > +struct ptm_getconfig {\n>> > +    union {\n>> > +        struct {\n>> > +            ptm_res tpm_result;\n>> > +            uint32_t flags;\n>> > +        } resp; /* response */\n>> > +    } u;\n>> > +};\n>> > +\n>> > +#define PTM_CONFIG_FLAG_FILE_KEY        0x1\n>> > +#define PTM_CONFIG_FLAG_MIGRATION_KEY   0x2\n>> > +\n>> > +\n>> > +typedef uint64_t ptm_cap;\n>> > +typedef struct ptm_est ptm_est;\n>> > +typedef struct ptm_reset_est ptm_reset_est;\n>> > +typedef struct ptm_loc ptm_loc;\n>> > +typedef struct ptm_hdata ptm_hdata;\n>> > +typedef struct ptm_init ptm_init;\n>> > +typedef struct ptm_getstate ptm_getstate;\n>> > +typedef struct ptm_setstate ptm_setstate;\n>> > +typedef struct ptm_getconfig ptm_getconfig;\n>> > +\n>> > +/* capability flags returned by PTM_GET_CAPABILITY */\n>> > +#define PTM_CAP_INIT               (1)\n>> > +#define PTM_CAP_SHUTDOWN           (1 << 1)\n>> > +#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)\n>> > +#define PTM_CAP_SET_LOCALITY       (1 << 3)\n>> > +#define PTM_CAP_HASHING            (1 << 4)\n>> > +#define PTM_CAP_CANCEL_TPM_CMD     (1 << 5)\n>> > +#define PTM_CAP_STORE_VOLATILE     (1 << 6)\n>> > +#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)\n>> > +#define PTM_CAP_GET_STATEBLOB      (1 << 8)\n>> > +#define PTM_CAP_SET_STATEBLOB      (1 << 9)\n>> > +#define PTM_CAP_STOP               (1 << 10)\n>> > +#define PTM_CAP_GET_CONFIG         (1 << 11)\n>> > +#define PTM_CAP_SET_DATAFD         (1 << 12)\n>> > +\n>> > +enum {\n>> > +    PTM_GET_CAPABILITY     = _IOR('P', 0, ptm_cap),\n>> > +    PTM_INIT               = _IOWR('P', 1, ptm_init),\n>> > +    PTM_SHUTDOWN           = _IOR('P', 2, ptm_res),\n>> > +    PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),\n>> > +    PTM_SET_LOCALITY       = _IOWR('P', 4, ptm_loc),\n>> > +    PTM_HASH_START         = _IOR('P', 5, ptm_res),\n>> > +    PTM_HASH_DATA          = _IOWR('P', 6, ptm_hdata),\n>> > +    PTM_HASH_END           = _IOR('P', 7, ptm_res),\n>> > +    PTM_CANCEL_TPM_CMD     = _IOR('P', 8, ptm_res),\n>> > +    PTM_STORE_VOLATILE     = _IOR('P', 9, ptm_res),\n>> > +    PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),\n>> > +    PTM_GET_STATEBLOB      = _IOWR('P', 11, ptm_getstate),\n>> > +    PTM_SET_STATEBLOB      = _IOWR('P', 12, ptm_setstate),\n>> > +    PTM_STOP               = _IOR('P', 13, ptm_res),\n>> > +    PTM_GET_CONFIG         = _IOR('P', 14, ptm_getconfig),\n>> > +    PTM_SET_DATAFD         = _IOR('P', 15, ptm_res),\n>> > +};\n>> > +\n>> > +/*\n>> > + * Commands used by the non-CUSE TPMs\n>> > + *\n>> > + * All messages container big-endian data.\n>> > + *\n>> > + * The return messages only contain the 'resp' part of the unions\n>> > + * in the data structures above. Besides that the limits in the\n>> > + * buffers above (ptm_hdata:u.req.data and\n>> > ptm_get_state:u.resp.data\n>> > + * and ptm_set_state:u.req.data) are 0xffffffff.\n>> > + */\n>> > +enum {\n>> > +    CMD_GET_CAPABILITY = 1,\n>> > +    CMD_INIT,\n>> > +    CMD_SHUTDOWN,\n>> > +    CMD_GET_TPMESTABLISHED,\n>> > +    CMD_SET_LOCALITY,\n>> > +    CMD_HASH_START,\n>> > +    CMD_HASH_DATA,\n>> > +    CMD_HASH_END,\n>> > +    CMD_CANCEL_TPM_CMD,\n>> > +    CMD_STORE_VOLATILE,\n>> > +    CMD_RESET_TPMESTABLISHED,\n>> > +    CMD_GET_STATEBLOB,\n>> > +    CMD_SET_STATEBLOB,\n>> > +    CMD_STOP,\n>> > +    CMD_GET_CONFIG,\n>> > +    CMD_SET_DATAFD\n>> > +};\n>> > +\n>> > +#endif /* _TPM_IOCTL_H */\n>> > diff --git a/qapi/tpm.json b/qapi/tpm.json\n>> > index e8b2d8d..7093f26 100644\n>> > --- a/qapi/tpm.json\n>> > +++ b/qapi/tpm.json\n>> > @@ -39,10 +39,12 @@\n>> >  # An enumeration of TPM types\n>> >  #\n>> >  # @passthrough: TPM passthrough type\n>> > +# @emulator: Software Emulator TPM type\n>> > +#            Since: 2.11\n>> >  #\n>> >  # Since: 1.5\n>> >  ##\n>> > -{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }\n>> > +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }\n>> >\n>> >  ##\n>> >  # @query-tpm-types:\n>> > @@ -56,7 +58,7 @@\n>> >  # Example:\n>> >  #\n>> >  # -> { \"execute\": \"query-tpm-types\" }\n>> > -# <- { \"return\": [ \"passthrough\" ] }\n>> > +# <- { \"return\": [ \"passthrough\", \"emulator\" ] }\n>> >  #\n>> >  ##\n>> >  { 'command': 'query-tpm-types', 'returns': ['TpmType'] }\n>> > @@ -77,16 +79,29 @@\n>> >                                               '*cancel-path' :\n>> > 'str'} }\n>> >\n>> >  ##\n>> > +# @TPMEmulatorOptions:\n>> > +#\n>> > +# Information about the TPM emulator type\n>> > +#\n>> > +# @chardev: Name of a unix socket chardev\n>> > +#\n>> > +# Since: 2.11\n>> > +##\n>> > +{ 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' } }\n>> > +\n>> > +##\n>> >  # @TpmTypeOptions:\n>> >  #\n>> >  # A union referencing different TPM backend types' configuration\n>> > options\n>> >  #\n>> >  # @type: 'passthrough' The configuration options for the TPM\n>> > passthrough type\n>> > +#        'emulator' The configuration options for TPM emulator\n>> > backend type\n>> >  #\n>> >  # Since: 1.5\n>> >  ##\n>> >  { 'union': 'TpmTypeOptions',\n>> > -   'data': { 'passthrough' : 'TPMPassthroughOptions' } }\n>> > +   'data': { 'passthrough' : 'TPMPassthroughOptions',\n>> > +             'emulator': 'TPMEmulatorOptions' } }\n>> >\n>> >  ##\n>> >  # @TPMInfo:\n>> > diff --git a/qemu-options.hx b/qemu-options.hx\n>> > index 77859a2..1e93e53 100644\n>> > --- a/qemu-options.hx\n>> > +++ b/qemu-options.hx\n>> > @@ -3121,7 +3121,9 @@ DEF(\"tpmdev\", HAS_ARG, QEMU_OPTION_tpmdev, \\\n>> >      \"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\\n\"\n>> >      \"                use path to provide path to a character\n>> > device; default is /dev/tpm0\\n\"\n>> >      \"                use cancel-path to provide path to TPM's\n>> > cancel sysfs entry; if\\n\"\n>> > -    \"                not provided it will be searched for in\n>> > /sys/class/misc/tpm?/device\\n\",\n>> > +    \"                not provided it will be searched for in\n>> > /sys/class/misc/tpm?/device\\n\"\n>> > +    \"-tpmdev emulator,id=id,chardev=dev\\n\"\n>> > +    \"                configure the TPM device using chardev\n>> > backend\\n\",\n>> >      QEMU_ARCH_ALL)\n>> >  STEXI\n>> >\n>> > @@ -3130,8 +3132,8 @@ The general form of a TPM device option is:\n>> >\n>> >  @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]\n>> >  @findex -tpmdev\n>> > -Backend type must be:\n>> > -@option{passthrough}.\n>> > +Backend type must be either one of the following:\n>> > +@option{passthrough}, @option{emulator}.\n>> >\n>> >  The specific backend type will determine the applicable options.\n>> >  The @code{-tpmdev} option creates the TPM backend and requires a\n>> > @@ -3181,6 +3183,20 @@ To create a passthrough TPM use the\n>> > following two options:\n>> >  Note that the @code{-tpmdev} id is @code{tpm0} and is referenced\n>> > by\n>> >  @code{tpmdev=tpm0} in the device option.\n>> >\n>> > +@item -tpmdev emulator, id=@var{id}, chardev=@var{dev}\n>> > +\n>> > +(Linux-host only) Enable access to a TPM emulator using Unix\n>> > domain socket based\n>> > +chardev backend.\n>> > +\n>> > +@option{chardev} specifies the unique ID of a character device\n>> > backend that provides connection to the software TPM server.\n>> > +\n>> > +To create a TPM emulator backend device with chardev socket\n>> > backend:\n>> > +@example\n>> > +\n>> > +-chardev socket,id=chrtpm,path=/tmp/swtpm-ctrl -tpmdev\n>> > emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0\n>> > +\n>> > +@end example\n>> > +\n>> >  @end table\n>> >\n>> >  ETEXI\n>> > --\n>> > 2.7.4\n>> >\n>>\n>>\n> - Amarnath","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"HyEteKs4\"; dkim-atps=neutral"],"Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y1gD93KRHz9ryk\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 26 Sep 2017 22:26:17 +1000 (AEST)","from localhost ([::1]:47346 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dwowJ-0005VJ-Jr\n\tfor incoming@patchwork.ozlabs.org; Tue, 26 Sep 2017 08:26:15 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:55649)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <marcandre.lureau@gmail.com>) id 1dwov5-0004w4-HS\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 08:25:04 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <marcandre.lureau@gmail.com>) id 1dwouw-00005O-D6\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 08:24:59 -0400","from mail-oi0-x236.google.com ([2607:f8b0:4003:c06::236]:55757)\n\tby eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16)\n\t(Exim 4.71) (envelope-from <marcandre.lureau@gmail.com>)\n\tid 1dwouw-0008W0-2j\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 08:24:50 -0400","by mail-oi0-x236.google.com with SMTP id x85so11572224oix.12\n\tfor <qemu-devel@nongnu.org>; Tue, 26 Sep 2017 05:24:48 -0700 (PDT)","by 10.58.17.173 with HTTP; Tue, 26 Sep 2017 05:24:46 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=mime-version:in-reply-to:references:from:date:message-id:subject:to\n\t:cc:content-transfer-encoding;\n\tbh=Nnn+aQH0fvje6wzRDbxrlSLCJ0pZG1DX3JffWyZlrKI=;\n\tb=HyEteKs4slwQVV10uqrEn2JGDSmu/k8bw2/j2nQtwbzDdVP/kKbC4Fm/WS2nWljytf\n\t39gRF6JZOJXrl58MnCvtbMdBO75iXoJTkR+FooX5KJ9f7K/9QoNFVT6zD1JBmjIu7J0t\n\tKiHXx3ViBvrLrJZPS/46TIdwI1FkToN5PkJTK4en7276kK6idE7WYW2jfHSq6+f+KPKg\n\tacNugYh6iIDcBxBJ99stni5aeOqObTLeQWHnt5B7pFUARi4IUk1XbiN05fQMpnpMr3/R\n\tMx2cuGHOzvjT/oyfgbZTWL30m4bYTj2sS+AvpS9bHUkMfHB6X8vR9B4zmHdBY6Kq+d42\n\trOdw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:in-reply-to:references:from:date\n\t:message-id:subject:to:cc:content-transfer-encoding;\n\tbh=Nnn+aQH0fvje6wzRDbxrlSLCJ0pZG1DX3JffWyZlrKI=;\n\tb=C0NejsKaCBmdofsCiUy2JHRAVrMofTgYGh1CB6MUVLyZe6wjHdch5XBRjIqGrOXc3z\n\tSwNjJtaAMQm91k+4XGnSrDTeRYQbT3S+0qk93HEx1PoygofVL4q9z2+i9cJ2bXv5OkY/\n\ti3BUu74NxfX2TDuJ5MpmTcvJ4zcfmv2GUk4cWw8s1lpkFFHTA4T6tJr+eUPdP6nJ75pS\n\tZ/1/qE5WOcknHHjmTyGhaoiSZHWuU8gYeA0tCVMo2+8/YgBC/dNzYnzPbc6Tp4Qa1TCE\n\tBS3cit2PTTm5RIhIimVfiyxrjAcleNCHwCQxu3mHaExgSGvwTO0RqkqPVJ5HVieVuZmo\n\tug4A==","X-Gm-Message-State":"AHPjjUib/20keJ0U059zchNOBAulAGK3zMLcNBjAB1pJLPUkjviiu7W1\n\tG9o3/vtIJspXf6omcOATrZ2Og1Yczw0EdClluDg=","X-Google-Smtp-Source":"AOwi7QBmXV3L2GYKK9CHes7sUAxQX2R9oroEIJGMLb6gD3NzQfyHQHq6It3dWNfLPd5TC0CyI+B/55V1fULfftx6oXE=","X-Received":"by 10.157.1.197 with SMTP id e63mr1867488ote.149.1506428687220; \n\tTue, 26 Sep 2017 05:24:47 -0700 (PDT)","MIME-Version":"1.0","In-Reply-To":"<1506427596.5843.104.camel@intel.com>","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>\n\t<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>\n\t<1506427596.5843.104.camel@intel.com>","From":"=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@gmail.com>","Date":"Tue, 26 Sep 2017 14:24:46 +0200","Message-ID":"<CAJ+F1CK_XRQG3W5A7tST5R1criUO3piohvMXNGyM348fTD7BhQ@mail.gmail.com>","To":"\"Valluri, Amarnath\" <amarnath.valluri@intel.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-detected-operating-system":"by eggs.gnu.org: Genre and OS details not\n\trecognized.","X-Received-From":"2607:f8b0:4003:c06::236","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"\"qemu-devel@nongnu.org\" <qemu-devel@nongnu.org>,\n\t\"armbru@redhat.com\" <armbru@redhat.com>,\n\t\"dgilbert@redhat.com\" <dgilbert@redhat.com>,\n\t\"stefanb@linux.vnet.ibm.com\" <stefanb@linux.vnet.ibm.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}},{"id":1775497,"web_url":"http://patchwork.ozlabs.org/comment/1775497/","msgid":"<1506432594.5843.107.camel@intel.com>","list_archive_url":null,"date":"2017-09-26T13:28:28","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":71320,"url":"http://patchwork.ozlabs.org/api/people/71320/","name":"Valluri, Amarnath","email":"amarnath.valluri@intel.com"},"content":"On Tue, 2017-09-26 at 14:24 +0200, Marc-André Lureau wrote:\r\n> Hi\r\n> \r\n> On Tue, Sep 26, 2017 at 2:05 PM, Valluri, Amarnath\r\n> <amarnath.valluri@intel.com> wrote:\r\n> > \r\n> > Hi Marc,\r\n> > \r\n> > Thanks for your time reviewing this patchset. Please find my inline\r\n> > comments.\r\n> > \r\n> > On Sun, 2017-09-24 at 20:52 +0200, Marc-André Lureau wrote:\r\n> > > \r\n> > > Hi\r\n> > > \r\n> > > Thanks for the nice update, removing the exec() code, using\r\n> > > chardev\r\n> > > and a private socketpair. Some comments below:\r\n> > > \r\n> > > On Fri, Sep 22, 2017 at 2:33 PM, Amarnath Valluri\r\n> > > <amarnath.valluri@intel.com> wrote:\r\n> > > > \r\n> > > > \r\n> > > > This change introduces a new TPM backend driver that can\r\n> > > > communicate with\r\n> > > > swtpm(software TPM emulator) using unix domain socket\r\n> > > > interface.\r\n> > > > QEMU talks to\r\n> > > > TPM emulator using socket based chardev backend device.\r\n> > > > \r\n> > > > Swtpm uses two Unix sockets for communications, one for plain\r\n> > > > TPM\r\n> > > > commands and\r\n> > > > responses, and one for out-of-band control messages. QEMU\r\n> > > > passes\r\n> > > > data socket\r\n> > > > been used over the control channel.\r\n> > > > \r\n> > > > The swtpm and associated tools can be found here:\r\n> > > >     https://github.com/stefanberger/swtpm\r\n> > > > \r\n> > > > The swtpm's control channel protocol specification can be found\r\n> > > > here:\r\n> > > >     https://github.com/stefanberger/swtpm/wiki/Control-Channel-\r\n> > > > Spec\r\n> > > > ification\r\n> > > > \r\n> > > > Usage:\r\n> > > >     # setup TPM state directory\r\n> > > >     mkdir /tmp/mytpm\r\n> > > >     chown -R tss:root /tmp/mytpm\r\n> > > >     /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek\r\n> > > > \r\n> > > >     # Ask qemu to use TPM emulator with given tpm state\r\n> > > > directory\r\n> > > >     qemu-system-x86_64 \\\r\n> > > >         [...] \\\r\n> > > >         -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \\\r\n> > > >         -tpmdev emulator,id=tpm0,chardev=chrtpm \\\r\n> > > >         -device tpm-tis,tpmdev=tpm0 \\\r\n> > > >         [...]\r\n> > > > \r\n> > > > Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>\r\n> > > > ---\r\n> > > >  configure             |  15 +-\r\n> > > >  hmp.c                 |   5 +\r\n> > > >  hw/tpm/Makefile.objs  |   1 +\r\n> > > >  hw/tpm/tpm_emulator.c | 649\r\n> > > > ++++++++++++++++++++++++++++++++++++++++++++++++++\r\n> > > >  hw/tpm/tpm_ioctl.h    | 246 +++++++++++++++++++\r\n> > > >  qapi/tpm.json         |  21 +-\r\n> > > >  qemu-options.hx       |  22 +-\r\n> > > >  7 files changed, 950 insertions(+), 9 deletions(-)\r\n> > > >  create mode 100644 hw/tpm/tpm_emulator.c\r\n> > > >  create mode 100644 hw/tpm/tpm_ioctl.h\r\n> > > > \r\n> > > > diff --git a/configure b/configure\r\n> > > > index cb0f7ed..ce2df2d 100755\r\n> > > > --- a/configure\r\n> > > > +++ b/configure\r\n> > > > @@ -3461,10 +3461,15 @@ fi\r\n> > > >  ##########################################\r\n> > > >  # TPM passthrough is only on x86 Linux\r\n> > > > \r\n> > > > -if test \"$targetos\" = Linux && test \"$cpu\" = i386 -o \"$cpu\" =\r\n> > > > x86_64; then\r\n> > > > -  tpm_passthrough=$tpm\r\n> > > > +if test \"$targetos\" = Linux; then\r\n> > > > +  tpm_emulator=$tpm\r\n> > > > +  if test \"$cpu\" = i386 -o \"$cpu\" = x86_64; then\r\n> > > > +    tpm_passthrough=$tpm\r\n> > > > +  else\r\n> > > > +    tpm_passthrough=no\r\n> > > > +  fi\r\n> > > >  else\r\n> > > > -  tpm_passthrough=no\r\n> > > > +  tpm_emulator=no\r\n> > > >  fi\r\n> > > > \r\n> > > >  ##########################################\r\n> > > > @@ -5359,6 +5364,7 @@ echo \"gcov enabled      $gcov\"\r\n> > > >  echo \"TPM support       $tpm\"\r\n> > > >  echo \"libssh2 support   $libssh2\"\r\n> > > >  echo \"TPM passthrough   $tpm_passthrough\"\r\n> > > > +echo \"TPM emulator      $tpm_emulator\"\r\n> > > >  echo \"QOM debugging     $qom_cast_debug\"\r\n> > > >  echo \"Live block migration $live_block_migration\"\r\n> > > >  echo \"lzo support       $lzo\"\r\n> > > > @@ -5943,6 +5949,9 @@ if test \"$tpm\" = \"yes\"; then\r\n> > > >    if test \"$tpm_passthrough\" = \"yes\"; then\r\n> > > >      echo \"CONFIG_TPM_PASSTHROUGH=y\" >> $config_host_mak\r\n> > > >    fi\r\n> > > > +  if test \"$tpm_emulator\" = \"yes\"; then\r\n> > > > +    echo \"CONFIG_TPM_EMULATOR=y\" >> $config_host_mak\r\n> > > It shouldn't require Linux, but posix (and I assume a port to\r\n> > > other\r\n> > > systems isn't impossible). same for build-sys / help / comments.\r\n> > I agree, Can you suggest, what is the Qemu way of limiting this to\r\n> > 'posix'.\r\n> > > \r\n> > > \r\n> there is CONFIG_POSIX\r\nOk, thanks. I will check\r\n> \r\n> > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +  fi\r\n> > > >  fi\r\n> > > > \r\n> > > >  echo \"TRACE_BACKENDS=$trace_backends\" >> $config_host_mak\r\n> > > > diff --git a/hmp.c b/hmp.c\r\n> > > > index cf62b2e..7e69eca 100644\r\n> > > > --- a/hmp.c\r\n> > > > +++ b/hmp.c\r\n> > > > @@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict\r\n> > > > *qdict)\r\n> > > >      Error *err = NULL;\r\n> > > >      unsigned int c = 0;\r\n> > > >      TPMPassthroughOptions *tpo;\r\n> > > > +    TPMEmulatorOptions *teo;\r\n> > > > \r\n> > > >      info_list = qmp_query_tpm(&err);\r\n> > > >      if (err) {\r\n> > > > @@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const\r\n> > > > QDict\r\n> > > > *qdict)\r\n> > > >                             tpo->has_cancel_path ? \",cancel-\r\n> > > > path=\"\r\n> > > > : \"\",\r\n> > > >                             tpo->has_cancel_path ? tpo-\r\n> > > > >cancel_path\r\n> > > > : \"\");\r\n> > > >              break;\r\n> > > > +        case TPM_TYPE_EMULATOR:\r\n> > > > +            teo = ti->options->u.emulator.data;\r\n> > > > +            monitor_printf(mon, \",chardev=%s\", teo->chardev);\r\n> > > > +            break;\r\n> > > >          case TPM_TYPE__MAX:\r\n> > > >              break;\r\n> > > >          }\r\n> > > > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs\r\n> > > > index 64cecc3..41f0b7a 100644\r\n> > > > --- a/hw/tpm/Makefile.objs\r\n> > > > +++ b/hw/tpm/Makefile.objs\r\n> > > > @@ -1,2 +1,3 @@\r\n> > > >  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o\r\n> > > >  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o\r\n> > > > tpm_util.o\r\n> > > > +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o\r\n> > > > diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c\r\n> > > > new file mode 100644\r\n> > > > index 0000000..c02bbe2\r\n> > > > --- /dev/null\r\n> > > > +++ b/hw/tpm/tpm_emulator.c\r\n> > > > @@ -0,0 +1,649 @@\r\n> > > > +/*\r\n> > > > + *  emulator TPM driver\r\n> > > > + *\r\n> > > > + *  Copyright (c) 2017 Intel Corporation\r\n> > > > + *  Author: Amarnath Valluri <amarnath.valluri@intel.com>\r\n> > > > + *\r\n> > > > + *  Copyright (c) 2010 - 2013 IBM Corporation\r\n> > > > + *  Authors:\r\n> > > > + *    Stefan Berger <stefanb@us.ibm.com>\r\n> > > > + *\r\n> > > > + *  Copyright (C) 2011 IAIK, Graz University of Technology\r\n> > > > + *    Author: Andreas Niederl\r\n> > > > + *\r\n> > > > + * This library is free software; you can redistribute it\r\n> > > > and/or\r\n> > > > + * modify it under the terms of the GNU Lesser General Public\r\n> > > > + * License as published by the Free Software Foundation;\r\n> > > > either\r\n> > > > + * version 2 of the License, or (at your option) any later\r\n> > > > version.\r\n> > > > + *\r\n> > > > + * This library is distributed in the hope that it will be\r\n> > > > useful,\r\n> > > > + * but WITHOUT ANY WARRANTY; without even the implied warranty\r\n> > > > of\r\n> > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See\r\n> > > > the\r\n> > > > GNU\r\n> > > > + * Lesser General Public License for more details.\r\n> > > > + *\r\n> > > > + * You should have received a copy of the GNU Lesser General\r\n> > > > Public\r\n> > > > + * License along with this library; if not, see <http://www.gn\r\n> > > > u.or\r\n> > > > g/licenses/>\r\n> > > > + *\r\n> > > > + */\r\n> > > > +\r\n> > > > +#include \"qemu/osdep.h\"\r\n> > > > +#include \"qemu/error-report.h\"\r\n> > > > +#include \"qemu/sockets.h\"\r\n> > > > +#include \"io/channel-socket.h\"\r\n> > > > +#include \"sysemu/tpm_backend.h\"\r\n> > > > +#include \"tpm_int.h\"\r\n> > > > +#include \"hw/hw.h\"\r\n> > > > +#include \"hw/i386/pc.h\"\r\n> > > > +#include \"tpm_util.h\"\r\n> > > > +#include \"tpm_ioctl.h\"\r\n> > > > +#include \"migration/blocker.h\"\r\n> > > > +#include \"qapi/error.h\"\r\n> > > > +#include \"chardev/char-fe.h\"\r\n> > > > +\r\n> > > > +#include <fcntl.h>\r\n> > > > +#include <sys/types.h>\r\n> > > > +#include <sys/stat.h>\r\n> > > > +#include <stdio.h>\r\n> > > > +\r\n> > > > +#define DEBUG_TPM 0\r\n> > > > +\r\n> > > > +#define DPRINT(fmt, ...) do { \\\r\n> > > > +    if (DEBUG_TPM) { \\\r\n> > > > +        fprintf(stderr, fmt, ## __VA_ARGS__); \\\r\n> > > > +    } \\\r\n> > > > +} while (0);\r\n> > > > +\r\n> > > > +#define DPRINTF(fmt, ...) DPRINT(\"tpm-emulator: \"fmt\"\\n\",\r\n> > > > __VA_ARGS__)\r\n> > > I would define a single DPRINTF() (& drop DPRINT usage below)\r\n> > Ok, will do\r\n> > > \r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +\r\n> > > > +#define TYPE_TPM_EMULATOR \"tpm-emulator\"\r\n> > > > +#define TPM_EMULATOR(obj) \\\r\n> > > > +    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)\r\n> > > > +\r\n> > > > +#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps &\r\n> > > > (cap)) == (cap))\r\n> > > > +\r\n> > > > +static const TPMDriverOps tpm_emulator_driver;\r\n> > > > +\r\n> > > > +/* data structures */\r\n> > > > +typedef struct TPMEmulator {\r\n> > > > +    TPMBackend parent;\r\n> > > > +\r\n> > > > +    TPMEmulatorOptions *options;\r\n> > > Contrary to my comment on previous patch, I realize it is\r\n> > > convenient\r\n> > > to have a qapi pointer here, so you can use the free visitor\r\n> > > later.\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    CharBackend ctrl_dev;\r\n> > > ctrl_chr perhaps? or just chr or be (the most common name in\r\n> > > other\r\n> > > devices).\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    QIOChannel *data_ioc;\r\n> > > > +    bool op_executing;\r\n> > > > +    bool op_canceled;\r\n> > > I think those 2 fields can be dropped, see below.\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    bool had_startup_error;\r\n> > > I think some little refactoring could remove the whole\r\n> > > had_startup_error() backend & callback before or after the\r\n> > > series.\r\n> > > tpm_backend_startup_tpm() already returns an error code.  device\r\n> > > or\r\n> > > common backend code could handle & remember that.\r\n> > Yes, i agree, we can avoid had_startup_error() from DriverOps, i\r\n> > will\r\n> > do this.\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    TPMVersion tpm_version;\r\n> > > This is probably worth to consider in common code instead, but\r\n> > > let's\r\n> > > not worry about it.\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    ptm_cap caps; /* capabilities of the TPM */\r\n> > > > +    uint8_t cur_locty_number; /* last set locality */\r\n> > > > +    QemuMutex state_lock;\r\n> > > > +    Error *migration_blocker;\r\n> > > > +} TPMEmulator;\r\n> > > > +\r\n> > > > +\r\n> > > > +static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned\r\n> > > > long\r\n> > > > cmd, void *msg,\r\n> > > > +                                size_t msg_len_in, size_t\r\n> > > > msg_len_out)\r\n> > > > +{\r\n> > > > +    uint32_t cmd_no = cpu_to_be32(cmd);\r\n> > > > +    ssize_t n = sizeof(uint32_t) + msg_len_in;\r\n> > > > +    uint8_t *buf = NULL;\r\n> > > > +\r\n> > > > +    buf = (uint8_t *)malloc(n);\r\n> > > could be g_alloca() instead. Alternatively, why not call 2\r\n> > > write()\r\n> > > instead?\r\n> > > \r\n> > > none of the casts in this function are necessary, please remove\r\n> > > them.\r\n> > Ok, will change to aclloca()\r\n> I just realized this is SOCK_SEQPACKET, ok\r\n> \r\n> > \r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    memcpy(buf, &cmd_no, sizeof(cmd_no));\r\n> > > > +    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);\r\n> > > > +\r\n> > > > +    n += qemu_chr_fe_write_all(dev, (const uint8_t *)buf, n);\r\n> > > weird\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    free(buf);\r\n> > > > +\r\n> > > > +    if (n > 0) {\r\n> > > with the n += above, you'll get interesting behaviour :)\r\n> > Ya, it was typo :)\r\n> > > \r\n> > > \r\n> > > You probably want to check if any write above failed, and return\r\n> > > early\r\n> > > for the error case.\r\n> > > \r\n> > > Please improve the error handling in this function\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        if (msg_len_out > 0) {\r\n> > > > +            n = qemu_chr_fe_read_all(dev, (uint8_t *)msg,\r\n> > > > msg_len_out);\r\n> > > > +            /* simulate ioctl return value */\r\n> > > > +            if (n > 0) {\r\n> > > > +                n = 0;\r\n> > > > +            }\r\n> > > > +        } else {\r\n> > > > +            n = 0;\r\n> > > > +        }\r\n> > > > +    }\r\n> > > > +    return n;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,\r\n> > > tpm_pt was tpm_passthrough I suppose.\r\n> > > \r\n> > > Please rename tpm_pt tpm_emu (or I would suggest \"self\", but this\r\n> > > isn't common name in qemu code - it's actually common in a close\r\n> > > c-object world., and it is quite convenient...)\r\n> > My interpretation about _pt was 'pointer' ;-) i will consider your\r\n> > suggetion.\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +                                     const uint8_t *in,\r\n> > > > uint32_t\r\n> > > > in_len,\r\n> > > > +                                     uint8_t *out, uint32_t\r\n> > > > out_len,\r\n> > > > +                                     bool *selftest_done)\r\n> > > > +{\r\n> > > > +    ssize_t ret;\r\n> > > > +    bool is_selftest = false;\r\n> > > > +    const struct tpm_resp_hdr *hdr = NULL;\r\n> > > > +    Error *err = NULL;\r\n> > > > +\r\n> > > > +    tpm_pt->op_canceled = false;\r\n> > > > +    tpm_pt->op_executing = true;\r\n> > > > +    if (selftest_done) {\r\n> > > > +        *selftest_done = false;\r\n> > > > +        is_selftest = tpm_util_is_selftest(in, in_len);\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    ret = qio_channel_write(tpm_pt->data_ioc, (char *)in,\r\n> > > > in_len,\r\n> > > > &err);\r\n> > > hmm, too bad qio_channel_write() doesn't take a void *\r\n> > > \r\n> > > why not write_all()?\r\n> > Agreed\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    if (ret != in_len || err) {\r\n> > > > +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\r\n> > > I don't think ECANCELED make sense for emulator code.\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +            error_report(\"tpm-emulator: error while\r\n> > > > transmitting\r\n> > > > data \"\r\n> > > > +                         \"to TPM: %s\", err ?\r\n> > > > error_get_pretty(err)\r\n> > > > : \"\");\r\n> > > > +            error_free(err);\r\n> > > > +        }\r\n> > > > +        goto err_exit;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    tpm_pt->op_executing = false;\r\n> > > > +\r\n> > > > +    ret = qio_channel_read(tpm_pt->data_ioc, (char *)out,\r\n> > > > out_len,\r\n> > > > &err);\r\n> > > > +    if (ret < 0 || err) {\r\n> > > read_all() ?\r\n> > The issue with read_all() is it does not return the no of bytes it\r\n> > read, so i would like to stict to _read()\r\n> ok\r\n> \r\n> > \r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        if (!tpm_pt->op_canceled || errno != ECANCELED) {\r\n> > > > +            error_report(\"tpm-emulator: error while reading\r\n> > > > data\r\n> > > > from \"\r\n> > > > +                         \"TPM: %s\", err ?\r\n> > > > error_get_pretty(err) :\r\n> > > > \"\");\r\n> > > > +            error_free(err);\r\n> > > > +        }\r\n> > > > +    } else if (ret >= sizeof(*hdr)) {\r\n> > > > +        hdr = (struct tpm_resp_hdr *)out;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    if (!hdr || be32_to_cpu(hdr->len) != ret) {\r\n> > > > +        error_report(\"tpm-emulator: received invalid response\r\n> > > > \"\r\n> > > > +                     \"packet from TPM with length :%ld\", ret);\r\n> > > > +        ret = -1;\r\n> > > > +        goto err_exit;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    if (is_selftest) {\r\n> > > > +        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    return 0;\r\n> > > > +\r\n> > > > +err_exit:\r\n> > > > +    if (ret < 0) {\r\n> > > > +        tpm_util_write_fatal_error_response(out, out_len);\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    tpm_pt->op_executing = false;\r\n> > > > +\r\n> > > > +    return ret;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static int tpm_emulator_set_locality(TPMEmulator *tpm_pt,\r\n> > > > uint8_t\r\n> > > > locty_number)\r\n> > > > +{\r\n> > > > +    ptm_loc loc;\r\n> > > > +\r\n> > > > +    DPRINTF(\"%s : locality: 0x%x\", __func__, locty_number);\r\n> > > > +\r\n> > > > +    if (tpm_pt->cur_locty_number != locty_number) {\r\n> > > return early instead if ==, to avoid code indent etc\r\n> > Ok\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        DPRINTF(\"setting locality : 0x%x\", locty_number);\r\n> > > > +        loc.u.req.loc = locty_number;\r\n> > > This number isn't set in be like the rest of the protocol?\r\n> > I doubt if i get ur point :(, can you please elaborate.\r\n> In the rest of the protocol, it uses big-endian. I suppose you should\r\n> cpu_to_be32(locty_number).\r\n> \r\n> > \r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > > > CMD_SET_LOCALITY, &loc,\r\n> > > > +                             sizeof(loc), sizeof(loc)) < 0) {\r\n> > > > +            error_report(\"tpm-emulator: could not set locality\r\n> > > > :\r\n> > > > %s\",\r\n> > > > +                         strerror(errno));\r\n> > > > +            return -1;\r\n> > > > +        }\r\n> > > > +        loc.u.resp.tpm_result =\r\n> > > > be32_to_cpu(loc.u.resp.tpm_result);\r\n> > > > +        if (loc.u.resp.tpm_result != 0) {\r\n> > > > +            error_report(\"tpm-emulator: TPM result for set\r\n> > > > locality : 0x%x\",\r\n> > > > +                         loc.u.resp.tpm_result);\r\n> > > > +            return -1;\r\n> > > > +        }\r\n> > > > +        tpm_pt->cur_locty_number = locty_number;\r\n> > > > +    }\r\n> > > > +    return 0;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static void tpm_emulator_handle_request(TPMBackend *tb,\r\n> > > > TPMBackendCmd cmd)\r\n> > > > +{\r\n> > > > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > > > +    TPMLocality *locty = NULL;\r\n> > > > +    bool selftest_done = false;\r\n> > > > +\r\n> > > > +    DPRINTF(\"processing command type %d\", cmd);\r\n> > > > +\r\n> > > > +    switch (cmd) {\r\n> > > > +    case TPM_BACKEND_CMD_PROCESS_CMD:\r\n> > > > +        qemu_mutex_lock(&tpm_pt->state_lock);\r\n> > > > +        locty = tb->tpm_state->locty_data;\r\n> > > > +        if (tpm_emulator_set_locality(tpm_pt,\r\n> > > > +                                      tb->tpm_state-\r\n> > > > >locty_number)\r\n> > > > < 0) {\r\n> > > > +            tpm_util_write_fatal_error_response(locty-\r\n> > > > > \r\n> > > > > r_buffer.buffer,\r\n> > > > +                                           locty-\r\n> > > > >r_buffer.size);\r\n> > > return / goto here instead of else.\r\n> > We should not retrun from here, we have to propagte the error\r\n> > response\r\n> > to device, and unlock the state.\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        } else {\r\n> > > > +            tpm_emulator_unix_tx_bufs(tpm_pt, locty-\r\n> > > > > \r\n> > > > > w_buffer.buffer,\r\n> > > > +                                              locty->w_offset,\r\n> > > > +                                              locty-\r\n> > > > > \r\n> > > > > r_buffer.buffer,\r\n> > > > +                                              locty-\r\n> > > > > \r\n> > > > > r_buffer.size,\r\n> > > > +                                              &selftest_done);\r\n> > > no error handling?\r\n> > The error case is supposed to handle by device, where we are\r\n> > filling\r\n> > into out buffer, using tpm_util_write_fatal_error_response().\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        }\r\n> > > > +\r\n> > > > +        tb->recv_data_callback(tb->tpm_state, tb->tpm_state-\r\n> > > > > \r\n> > > > > locty_number,\r\n> > > > +                               selftest_done);\r\n> > > > +        qemu_mutex_unlock(&tpm_pt->state_lock);\r\n> > > > +\r\n> > > > +        break;\r\n> > > > +    case TPM_BACKEND_CMD_INIT:\r\n> > > > +    case TPM_BACKEND_CMD_END:\r\n> > > > +    case TPM_BACKEND_CMD_TPM_RESET:\r\n> > > > +        /* nothing to do */\r\n> > > > +        break;\r\n> > > > +    }\r\n> > > > +}\r\n> > > > +\r\n> > > > +/*\r\n> > > > + * Gracefully shut down the external unixio TPM\r\n> > > > + */\r\n> > > > +static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)\r\n> > > > +{\r\n> > > > +    ptm_res res;\r\n> > > > +\r\n> > > > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_SHUTDOWN,\r\n> > > > &res, 0,\r\n> > > > +                         sizeof(res)) < 0) {\r\n> > > > +        error_report(\"tpm-emulator: Could not cleanly shutdown\r\n> > > > the\r\n> > > > TPM: %s\",\r\n> > > > +                     strerror(errno));\r\n> > > > +    } else if (res != 0) {\r\n> > > > +        error_report(\"tpm-emulator: TPM result for sutdown:\r\n> > > > 0x%x\",\r\n> > > > +                     be32_to_cpu(res));\r\n> > > > +    }\r\n> > > > +}\r\n> > > > +\r\n> > > > +static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)\r\n> > > > +{\r\n> > > > +    DPRINTF(\"%s\", __func__);\r\n> > > > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > > > CMD_GET_CAPABILITY,\r\n> > > > +                         &tpm_pt->caps, 0, sizeof(tpm_pt-\r\n> > > > >caps)) <\r\n> > > > 0) {\r\n> > > > +        error_report(\"tpm-emulator: probing failed : %s\",\r\n> > > > strerror(errno));\r\n> > > > +        return -1;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    tpm_pt->caps = be64_to_cpu(tpm_pt->caps);\r\n> > > > +\r\n> > > > +    DPRINTF(\"capbilities : 0x%lx\", tpm_pt->caps);\r\n> > > > +\r\n> > > > +    return 0;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)\r\n> > > > +{\r\n> > > > +    ptm_cap caps = 0;\r\n> > > > +    const char *tpm = NULL;\r\n> > > > +\r\n> > > > +    /* check for min. required capabilities */\r\n> > > > +    switch (tpm_pt->tpm_version) {\r\n> > > > +    case TPM_VERSION_1_2:\r\n> > > > +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |\r\n> > > > PTM_CAP_GET_TPMESTABLISHED |\r\n> > > > +               PTM_CAP_SET_LOCALITY;\r\n> > > > +        tpm = \"1.2\";\r\n> > > > +        break;\r\n> > > > +    case TPM_VERSION_2_0:\r\n> > > > +        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |\r\n> > > > PTM_CAP_GET_TPMESTABLISHED |\r\n> > > > +               PTM_CAP_SET_LOCALITY |\r\n> > > > PTM_CAP_RESET_TPMESTABLISHED;\r\n> > > > +        tpm = \"2\";\r\n> > > > +        break;\r\n> > > > +    case TPM_VERSION_UNSPEC:\r\n> > > > +        error_report(\"tpm-emulator: TPM version has not been\r\n> > > > set\");\r\n> > > > +        return -1;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {\r\n> > > > +        error_report(\"tpm-emulator: TPM does not implement\r\n> > > > minimum\r\n> > > > set of \"\r\n> > > > +                     \"required capabilities for TPM %s\r\n> > > > (0x%x)\",\r\n> > > > tpm, (int)caps);\r\n> > > > +        return -1;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    return 0;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static int tpm_emulator_startup_tpm(TPMBackend *tb)\r\n> > > > +{\r\n> > > > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > > > +    ptm_init init;\r\n> > > > +    ptm_res res;\r\n> > > > +\r\n> > > > +    DPRINTF(\"%s\", __func__);\r\n> > > > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev, CMD_INIT,\r\n> > > > &init,\r\n> > > > sizeof(init),\r\n> > > > +                         sizeof(init)) < 0) {\r\n> > > > +        error_report(\"tpm-emulator: could not send INIT: %s\",\r\n> > > > +                     strerror(errno));\r\n> > > > +        goto err_exit;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    res = be32_to_cpu(init.u.resp.tpm_result);\r\n> > > > +    if (res) {\r\n> > > > +        error_report(\"tpm-emulator: TPM result for CMD_INIT:\r\n> > > > 0x%x\", res);\r\n> > > > +        goto err_exit;\r\n> > > > +    }\r\n> > > > +    return 0;\r\n> > > > +\r\n> > > > +err_exit:\r\n> > > > +    tpm_pt->had_startup_error = true;\r\n> > > > +    return -1;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static bool tpm_emulator_get_tpm_established_flag(TPMBackend\r\n> > > > *tb)\r\n> > > > +{\r\n> > > > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > > > +    ptm_est est;\r\n> > > > +\r\n> > > > +    DPRINTF(\"%s\", __func__);\r\n> > > > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > > > CMD_GET_TPMESTABLISHED, &est, 0,\r\n> > > > +                         sizeof(est)) < 0) {\r\n> > > > +        error_report(\"tpm-emulator: Could not get the TPM\r\n> > > > established flag: %s\",\r\n> > > > +                     strerror(errno));\r\n> > > > +        return false;\r\n> > > > +    }\r\n> > > > +    DPRINTF(\"established flag: %0x\", est.u.resp.bit);\r\n> > > > +\r\n> > > > +    return (est.u.resp.bit != 0);\r\n> > > > +}\r\n> > > > +\r\n> > > > +static int tpm_emulator_reset_tpm_established_flag(TPMBackend\r\n> > > > *tb,\r\n> > > > +                                                   uint8_t\r\n> > > > locty)\r\n> > > > +{\r\n> > > > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > > > +    ptm_reset_est reset_est;\r\n> > > > +    ptm_res res;\r\n> > > > +\r\n> > > > +    /* only a TPM 2.0 will support this */\r\n> > > > +    if (tpm_pt->tpm_version == TPM_VERSION_2_0) {\r\n> > > > +        reset_est.u.req.loc = tpm_pt->cur_locty_number;\r\n> > > > +\r\n> > > > +        if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > > > CMD_RESET_TPMESTABLISHED,\r\n> > > > +                                 &reset_est,\r\n> > > > sizeof(reset_est),\r\n> > > > +                                 sizeof(reset_est)) < 0) {\r\n> > > > +            error_report(\"tpm-emulator: Could not reset the\r\n> > > > establishment bit: \"\r\n> > > > +                          \"%s\", strerror(errno));\r\n> > > > +            return -1;\r\n> > > > +        }\r\n> > > > +\r\n> > > > +        res = be32_to_cpu(reset_est.u.resp.tpm_result);\r\n> > > > +        if (res) {\r\n> > > > +            error_report(\"tpm-emulator: TPM result for rest\r\n> > > > establixhed flag: \"\r\n> > > > +                         \"0x%x\", res);\r\n> > > > +            return -1;\r\n> > > > +        }\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    return 0;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static bool tpm_emulator_had_startup_error(TPMBackend *tb)\r\n> > > > +{\r\n> > > > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > > > +\r\n> > > > +    return tpm_pt->had_startup_error;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static void tpm_emulator_cancel_cmd(TPMBackend *tb)\r\n> > > > +{\r\n> > > > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > > > +    ptm_res res;\r\n> > > > +\r\n> > > > +    /*\r\n> > > > +     * As of Linux 3.7 the tpm_tis driver does not properly\r\n> > > > cancel\r\n> > > > +     * commands on all TPM manufacturers' TPMs.\r\n> > > > +     * Only cancel if we're busy so we don't cancel someone\r\n> > > > else's\r\n> > > > +     * command, e.g., a command executed on the host.\r\n> > > > +     */\r\n> > > > +    if (tpm_pt->op_executing) {\r\n> > > The field is set in the worker thread. This is racy. Fortunately\r\n> > > this\r\n> > > is not relevant for emulator, I think you can simply drop that\r\n> > > check\r\n> > > and the variable. Stefan should confirm though.\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        if (TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt,\r\n> > > > PTM_CAP_CANCEL_TPM_CMD)) {\r\n> > > > +            if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > > > CMD_CANCEL_TPM_CMD,\r\n> > > > +                                     &res, 0, sizeof(res)) <\r\n> > > > 0) {\r\n> > > > +                error_report(\"tpm-emulator: Could not cancel\r\n> > > > command: %s\",\r\n> > > > +                             strerror(errno));\r\n> > > > +            } else if (res != 0) {\r\n> > > > +                error_report(\"tpm-emulator: Failed to cancel\r\n> > > > TPM:\r\n> > > > 0x%x\",\r\n> > > > +                             be32_to_cpu(res));\r\n> > > > +            } else {\r\n> > > > +                tpm_pt->op_canceled = true;\r\n> > > > +            }\r\n> > > > +        }\r\n> > > > +    }\r\n> > > > +}\r\n> > > > +\r\n> > > > +static void tpm_emulator_reset(TPMBackend *tb)\r\n> > > > +{\r\n> > > > +    DPRINTF(\"%s\", __func__);\r\n> > > > +\r\n> > > > +    tpm_emulator_cancel_cmd(tb);\r\n> > > > +}\r\n> > > > +\r\n> > > > +static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)\r\n> > > > +{\r\n> > > > +    TPMEmulator *tpm_pt = TPM_EMULATOR(tb);\r\n> > > > +\r\n> > > > +    return tpm_pt->tpm_version;\r\n> > > > +}\r\n> > > > +\r\n> > > > +static void tpm_emulator_block_migration(TPMEmulator *tpm_pt)\r\n> > > > +{\r\n> > > > +    Error *err = NULL;\r\n> > > > +\r\n> > > > +    error_setg(&tpm_pt->migration_blocker,\r\n> > > > +               \"Migration disabled: TPM emulator not yet\r\n> > > > migratable\");\r\n> > > > +    migrate_add_blocker(tpm_pt->migration_blocker, &err);\r\n> > > > +    if (err) {\r\n> > > > +        error_free(err);\r\n> > > probably better to report_err it instead\r\n> > Ok\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        error_free(tpm_pt->migration_blocker);\r\n> > > > +        tpm_pt->migration_blocker = NULL;\r\n> > > and return an error code.\r\n> > Will do\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +    }\r\n> > > > +}\r\n> > > > +\r\n> > > > +static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_pt)\r\n> > > > +{\r\n> > > > +    ptm_res res;\r\n> > > > +    Error *err = NULL;\r\n> > > > +    int fds[2] = { -1, -1 };\r\n> > > > +\r\n> > > > +    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {\r\n> > > > +        error_report(\"tpm-emulator: Failed to create\r\n> > > > socketpair\");\r\n> > > > +        return -1;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    qemu_chr_fe_set_msgfds(&tpm_pt->ctrl_dev, fds + 1, 1);\r\n> > > > +\r\n> > > > +    if (tpm_emulator_ctrlcmd(&tpm_pt->ctrl_dev,\r\n> > > > CMD_SET_DATAFD,\r\n> > > > &res, 0,\r\n> > > > +                    sizeof(res)) || res != 0) {\r\n> > > Yay! for making life easier and hiding a protocol detail.\r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        error_report(\"tpm-emulator: Failed to send\r\n> > > > CMD_SET_DATAFD:\r\n> > > > %s\",\r\n> > > > +                     strerror(errno));\r\n> > > > +        goto err_exit;\r\n> > > > +    }\r\n> > > > +\r\n> > > > +    tpm_pt->data_ioc =\r\n> > > > QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));\r\n> > > > +    if (err) {\r\n> > > > +        error_report(\"tpm-emulator: Failed to create io\r\n> > > > channel :\r\n> > > > %s\",\r\n> > > > +                       error_get_pretty(err));\r\n> > > error_prepend()?\r\n> > Ok\r\n> > > \r\n> > > \r\n> > > > \r\n> > > > \r\n> > > > +        error_free(err);\r\n> > > > +        goto err_exit;\r\n> > > > +    }\r\n> > > close fds[1] ?\r\n> > I guess we are not supposed to close the other end of the\r\n> > socketpair/pipe, as it is not forked process.\r\n> You will close this end, not the other end.\r\nfds[1] is handed over to other end, fds[0] is used by qemu, so we\r\ncannot close unless error case i guess.\r\n\r\n- Amarnath","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":"ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y1hdQ6Sqbz9tXH\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 26 Sep 2017 23:29:46 +1000 (AEST)","from localhost ([::1]:47561 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dwpvl-0001yK-2J\n\tfor incoming@patchwork.ozlabs.org; Tue, 26 Sep 2017 09:29:45 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:46738)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <amarnath.valluri@intel.com>) id 1dwpug-0001dT-LQ\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:28:42 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <amarnath.valluri@intel.com>) id 1dwpuc-0001nf-HT\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:28:38 -0400","from mga06.intel.com ([134.134.136.31]:62778)\n\tby eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <amarnath.valluri@intel.com>)\n\tid 1dwpub-0001ms-W1\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:28:34 -0400","from fmsmga004.fm.intel.com ([10.253.24.48])\n\tby orsmga104.jf.intel.com with ESMTP; 26 Sep 2017 06:28:32 -0700","from irsmsx102.ger.corp.intel.com ([163.33.3.155])\n\tby fmsmga004.fm.intel.com with ESMTP; 26 Sep 2017 06:28:30 -0700","from irsmsx110.ger.corp.intel.com ([169.254.15.8]) by\n\tIRSMSX102.ger.corp.intel.com ([169.254.2.180]) with mapi id\n\t14.03.0319.002; Tue, 26 Sep 2017 14:28:29 +0100"],"X-ExtLoop1":"1","X-IronPort-AV":"E=Sophos;i=\"5.42,440,1500966000\"; d=\"scan'208\";a=\"316345082\"","From":"\"Valluri, Amarnath\" <amarnath.valluri@intel.com>","To":"\"marcandre.lureau@gmail.com\" <marcandre.lureau@gmail.com>","Thread-Topic":"[Qemu-devel][PATCH v7 8/8] tpm: Added support for TPM emulator","Thread-Index":"AQHTM576djiiRLAX70GsKUQXwgH+3KLEVJYAgAKzNQCAAAUUAIAAEjIA","Date":"Tue, 26 Sep 2017 13:28:28 +0000","Message-ID":"<1506432594.5843.107.camel@intel.com>","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>\n\t<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>\n\t<1506427596.5843.104.camel@intel.com>\n\t<CAJ+F1CK_XRQG3W5A7tST5R1criUO3piohvMXNGyM348fTD7BhQ@mail.gmail.com>","In-Reply-To":"<CAJ+F1CK_XRQG3W5A7tST5R1criUO3piohvMXNGyM348fTD7BhQ@mail.gmail.com>","Accept-Language":"en-US","Content-Language":"en-US","X-MS-Has-Attach":"","X-MS-TNEF-Correlator":"","x-originating-ip":"[10.237.68.147]","Content-Type":"text/plain; charset=\"utf-8\"","Content-ID":"<09372A59DE5A4546A5DF187E9058DF03@intel.com>","Content-Transfer-Encoding":"base64","MIME-Version":"1.0","X-detected-operating-system":"by eggs.gnu.org: Genre and OS details not\n\trecognized.","X-Received-From":"134.134.136.31","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"\"qemu-devel@nongnu.org\" <qemu-devel@nongnu.org>,\n\t\"armbru@redhat.com\" <armbru@redhat.com>,\n\t\"dgilbert@redhat.com\" <dgilbert@redhat.com>,\n\t\"stefanb@linux.vnet.ibm.com\" <stefanb@linux.vnet.ibm.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}},{"id":1775542,"web_url":"http://patchwork.ozlabs.org/comment/1775542/","msgid":"<CAJ+F1CLv6PVPwx7UwSMf74-1RxMbbES3+2jnuN=hyXiSHuEWzw@mail.gmail.com>","list_archive_url":null,"date":"2017-09-26T13:55:05","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":6442,"url":"http://patchwork.ozlabs.org/api/people/6442/","name":"Marc-André Lureau","email":"marcandre.lureau@gmail.com"},"content":"Hi\n\nOn Tue, Sep 26, 2017 at 3:28 PM, Valluri, Amarnath\n<amarnath.valluri@intel.com> wrote:\n> On Tue, 2017-09-26 at 14:24 +0200, Marc-André Lureau wrote:\n>> > > close fds[1] ?\n>> > I guess we are not supposed to close the other end of the\n>> > socketpair/pipe, as it is not forked process.\n>> You will close this end, not the other end.\n> fds[1] is handed over to other end, fds[0] is used by qemu, so we\n> cannot close unless error case i guess.\n\nYou should be able to close fds[1] in qemu, and keep the communication\nworking between the two processes. If you don't close, it will leak a\nfd in qemu.","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"n41rCCZ4\"; dkim-atps=neutral"],"Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y1jC941dSz9tXK\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 26 Sep 2017 23:55:32 +1000 (AEST)","from localhost ([::1]:47669 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dwqKf-0001BS-J3\n\tfor incoming@patchwork.ozlabs.org; Tue, 26 Sep 2017 09:55:29 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:54523)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <marcandre.lureau@gmail.com>) id 1dwqKJ-0001BE-Ow\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:55:08 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <marcandre.lureau@gmail.com>) id 1dwqKI-0000Ln-Vf\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:55:07 -0400","from mail-oi0-x243.google.com ([2607:f8b0:4003:c06::243]:33070)\n\tby eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16)\n\t(Exim 4.71) (envelope-from <marcandre.lureau@gmail.com>)\n\tid 1dwqKI-0000LW-RL\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:55:06 -0400","by mail-oi0-x243.google.com with SMTP id z73so6243679oia.0\n\tfor <qemu-devel@nongnu.org>; Tue, 26 Sep 2017 06:55:06 -0700 (PDT)","by 10.58.17.173 with HTTP; Tue, 26 Sep 2017 06:55:05 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=mime-version:in-reply-to:references:from:date:message-id:subject:to\n\t:cc:content-transfer-encoding;\n\tbh=AHkAR0SPFEtRAYt/kTcVEJHuYz37ndg4v6VYLWoHbf0=;\n\tb=n41rCCZ4Yywv5k0PkUnir+LBIxD7uHLwIxx4BuOskEA/HiBvIz4Q5msINedklwOtZV\n\tgLg0XcjmbUT0s1xJIfJpYUBVIJqx9/Qw2m+xDV2bLlkAAzqbwvzFwnIG6LpX9ZdwjVh1\n\ti/wL7bCB3fgz9FjddEQHmSS/zTDE12TkRG42tfgF9IWXFi7Aa++LyOTVFDlTrySSnezo\n\tFuPhDjauQStBEiCm/LkdxW1v91YL951GoCz5ZBzjXK1tG2fvhJ1BkfASfG7jFjdttzbf\n\t+egqq2dOmZddRfmBm3sRN8ml0q8gH5iBAkR326RqMMSiE6QP5at0EVhoATb0yI6djnD3\n\tI+Fw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:in-reply-to:references:from:date\n\t:message-id:subject:to:cc:content-transfer-encoding;\n\tbh=AHkAR0SPFEtRAYt/kTcVEJHuYz37ndg4v6VYLWoHbf0=;\n\tb=AMvbXAAeYon9NVN/NUh7ZbqIY4mGcp3i5A9maujleeSQK2Nru91N5uq1NlGnjtg+/h\n\tnP3LaYbvS1a5sOT9RjvHBNCA5jI/H4NezrIw1O3ZtDdvDlzlmlr236cVBIPj6vMLOWbc\n\tUOBMM+Z1B0soWnfc1uE7vuePHxdMVhQXMAyLRF4nKhfmifWM8rnGQny8nyIr/+7WvzL2\n\tJXvrnRRjQu/tWwv5/Xzxp9IH6FqZGOT5rw9+atQL9SaOalX99854oWl2MPeNEFZOPNVv\n\tuQ1Azrnx+7PuMacZxzTN8CEdGFxtUwsYU0Wx323cg/NXrGi2s3tS1wla2UtN20W69t3E\n\tFHvg==","X-Gm-Message-State":"AHPjjUj2hh4wlGZh/QCbHPg7Jbj81x79aI6i0WoVxlZOpQjBBoc42sQa\n\tMQ6MZ7olIdkaCFYnY7MbvXVYbK46pJ6El9kl8X0=","X-Google-Smtp-Source":"AOwi7QDZVSl8HvZTwxdrNEGMwRhiSWi4i2UqiJl9l/J4GnIBj/RZyoQ/xud9S6aRUabdXvA33Yj92LZOGlk+J3x/RtM=","X-Received":"by 10.157.3.85 with SMTP id 79mr2286780otv.165.1506434105899;\n\tTue, 26 Sep 2017 06:55:05 -0700 (PDT)","MIME-Version":"1.0","In-Reply-To":"<1506432594.5843.107.camel@intel.com>","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>\n\t<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>\n\t<1506427596.5843.104.camel@intel.com>\n\t<CAJ+F1CK_XRQG3W5A7tST5R1criUO3piohvMXNGyM348fTD7BhQ@mail.gmail.com>\n\t<1506432594.5843.107.camel@intel.com>","From":"=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@gmail.com>","Date":"Tue, 26 Sep 2017 15:55:05 +0200","Message-ID":"<CAJ+F1CLv6PVPwx7UwSMf74-1RxMbbES3+2jnuN=hyXiSHuEWzw@mail.gmail.com>","To":"\"Valluri, Amarnath\" <amarnath.valluri@intel.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-detected-operating-system":"by eggs.gnu.org: Genre and OS details not\n\trecognized.","X-Received-From":"2607:f8b0:4003:c06::243","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"\"qemu-devel@nongnu.org\" <qemu-devel@nongnu.org>,\n\t\"armbru@redhat.com\" <armbru@redhat.com>,\n\t\"dgilbert@redhat.com\" <dgilbert@redhat.com>,\n\t\"stefanb@linux.vnet.ibm.com\" <stefanb@linux.vnet.ibm.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}},{"id":1775549,"web_url":"http://patchwork.ozlabs.org/comment/1775549/","msgid":"<d0ae0926-cf82-2ce7-39e2-d17d6db70d68@redhat.com>","list_archive_url":null,"date":"2017-09-26T13:59:33","subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","submitter":{"id":6591,"url":"http://patchwork.ozlabs.org/api/people/6591/","name":"Eric Blake","email":"eblake@redhat.com"},"content":"On 09/26/2017 07:05 AM, Valluri, Amarnath wrote:\n\n>>> +\n>>> +#define DPRINT(fmt, ...) do { \\\n>>> +    if (DEBUG_TPM) { \\\n>>> +        fprintf(stderr, fmt, ## __VA_ARGS__); \\\n>>> +    } \\\n>>> +} while (0);\n\nDo not include the trailing ';' directly in the macro definition. The\nwhole point of wrapping things in a do{}while(0) is so that you can do:\n\nif (foo)\n    DPRINT(...);\nelse\n    ...\n\n(of course, that violates our coding style, as we require {} everywhere,\nbut it makes your macro appropriate for copying and pasting to other\nprojects that have different styles).\n\n\n>>> +    ret = qio_channel_read(tpm_pt->data_ioc, (char *)out, out_len,\n>>> &err);\n>>> +    if (ret < 0 || err) {\n>> read_all() ?\n> The issue with read_all() is it does not return the no of bytes it\n> read, so i would like to stict to _read()\n\nBut you KNOW the number of bytes read if read_all() succeeded - it read\nas many bytes as you requested!","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","ext-mx08.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com","ext-mx08.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=eblake@redhat.com"],"Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y1jJM20ZXz9t43\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 27 Sep 2017 00:00:03 +1000 (AEST)","from localhost ([::1]:47683 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dwqP3-0003sU-Fd\n\tfor incoming@patchwork.ozlabs.org; Tue, 26 Sep 2017 10:00:01 -0400","from eggs.gnu.org ([2001:4830:134:3::10]:55911)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <eblake@redhat.com>) id 1dwqOf-0003sE-SO\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:59:39 -0400","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <eblake@redhat.com>) id 1dwqOe-0002Vj-RU\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:59:37 -0400","from mx1.redhat.com ([209.132.183.28]:33036)\n\tby eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <eblake@redhat.com>) id 1dwqOe-0002VJ-Ew\n\tfor qemu-devel@nongnu.org; Tue, 26 Sep 2017 09:59:36 -0400","from smtp.corp.redhat.com\n\t(int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby mx1.redhat.com (Postfix) with ESMTPS id 122BFC057F91;\n\tTue, 26 Sep 2017 13:59:35 +0000 (UTC)","from [10.10.124.97] (ovpn-124-97.rdu2.redhat.com [10.10.124.97])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id 00CAF600CA;\n\tTue, 26 Sep 2017 13:59:33 +0000 (UTC)"],"DMARC-Filter":"OpenDMARC Filter v1.3.2 mx1.redhat.com 122BFC057F91","To":"\"Valluri, Amarnath\" <amarnath.valluri@intel.com>,\n\t\"marcandre.lureau@gmail.com\" <marcandre.lureau@gmail.com>","References":"<1506083624-20621-1-git-send-email-amarnath.valluri@intel.com>\n\t<1506083624-20621-9-git-send-email-amarnath.valluri@intel.com>\n\t<CAJ+F1CKrNWcJhpsyxa8ENKfJzaSi=wz5-s+LV06K8o7xUsgdeA@mail.gmail.com>\n\t<1506427596.5843.104.camel@intel.com>","From":"Eric Blake <eblake@redhat.com>","Openpgp":"url=http://people.redhat.com/eblake/eblake.gpg","Organization":"Red Hat, Inc.","Message-ID":"<d0ae0926-cf82-2ce7-39e2-d17d6db70d68@redhat.com>","Date":"Tue, 26 Sep 2017 08:59:33 -0500","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\n\tThunderbird/52.3.0","MIME-Version":"1.0","In-Reply-To":"<1506427596.5843.104.camel@intel.com>","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\";\n\tboundary=\"P2ADmFtPTcLWiOiDkXFRxLSdLV6nlQUtS\"","X-Scanned-By":"MIMEDefang 2.79 on 10.5.11.11","X-Greylist":"Sender IP whitelisted, not delayed by milter-greylist-4.5.16\n\t(mx1.redhat.com [10.5.110.32]);\n\tTue, 26 Sep 2017 13:59:35 +0000 (UTC)","X-detected-operating-system":"by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic]\n\t[fuzzy]","X-Received-From":"209.132.183.28","X-Content-Filtered-By":"Mailman/MimeDel 2.1.21","Subject":"Re: [Qemu-devel] [PATCH v7 8/8] tpm: Added support for TPM emulator","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"\"qemu-devel@nongnu.org\" <qemu-devel@nongnu.org>,\n\t\"armbru@redhat.com\" <armbru@redhat.com>,\n\t\"dgilbert@redhat.com\" <dgilbert@redhat.com>,\n\t\"stefanb@linux.vnet.ibm.com\" <stefanb@linux.vnet.ibm.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}}]