qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform
@ 2019-12-12 18:07 Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 1/8] tpm_spapr: Support TPM for ppc64 using CRQ based interface Stefan Berger
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc; +Cc: marcandre.lureau, Stefan Berger, qemu-devel, david

The following series of patches adds vTPM emulator support for the
ppc64 platform (pSeries). 

It can be tested as follows with swtpm/libtpms:

mkdir /tmp/mytpm1
swtpm socket --tpmstate dir=/tmp/mytpm1 \
  --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \
  --log level=20

If TPM 2 is desired, add --tpm2 as parameter to the above.

In another terminal start QEMU:

sudo ./ppc64-softmmu/qemu-system-ppc64 -display sdl \
	-machine pseries,accel=kvm \
	-m 1024 -bios slof.bin -boot menu=on \
	-nodefaults -device VGA -device pci-ohci -device usb-kbd \
	-chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \
	-tpmdev emulator,id=tpm0,chardev=chrtpm \
	-device tpm-spapr,tpmdev=tpm0 \
	-device spapr-vscsi,id=scsi0,reg=0x00002000 \
	-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \
	-drive file=test.img,format=raw,if=none,id=drive-virtio-disk0

Links:
 - libtpms: https://github.com/stefanberger/libtpms/wiki
 - swtpm: https://github.com/stefanberger/swtpm/wiki

Changes:
 v3->v4:
  - addressed comments to v3
  - reworked suspend/resume support that requires extensions to backends

 v2->v3:
  - patch 1: a TPM 2 is identified by IBM,vtpm20 in the compatible node
  - patch 1: convert to tracing to display Tx and Rx buffers
  - added documentation patch
  - added patch to enable TPM device as part of pSeries

 v1->v2:
  - followed Cedric Le Goater's suggestions to patch 1
  - send appropriate CRQ error responses if DMA read or write fails
  - renamed tpm_spapr_got_payload to tpm_spapr_process_cmd and
    pass endianess-adjusted data pointer from CRQ to it

Regards,
    Stefan

Stefan Berger (8):
  tpm_spapr: Support TPM for ppc64 using CRQ based interface
  tpm_backend: Implement check whether tpm backend is suspended
  tpm_emulator: Implement callback for whether we are suspended
  tpm_passthrough: Implement callback for whether we are suspended
  tpm: Return bool from tpm_backend_finish_sync
  tpm_spapr: Support suspend and resume
  hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES config
  docs: tpm: Add example command line for ppc64 and tpm-spapr

 backends/tpm.c               |  13 +-
 docs/specs/tpm.txt           |  20 +-
 hw/ppc/Kconfig               |   1 +
 hw/tpm/Kconfig               |   6 +
 hw/tpm/Makefile.objs         |   1 +
 hw/tpm/tpm_emulator.c        |  12 +
 hw/tpm/tpm_passthrough.c     |   6 +
 hw/tpm/tpm_spapr.c           | 460 +++++++++++++++++++++++++++++++++++
 hw/tpm/trace-events          |  14 ++
 include/sysemu/tpm.h         |   3 +
 include/sysemu/tpm_backend.h |  16 +-
 qapi/tpm.json                |   6 +-
 12 files changed, 552 insertions(+), 6 deletions(-)
 create mode 100644 hw/tpm/tpm_spapr.c

-- 
2.21.0



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v4 1/8] tpm_spapr: Support TPM for ppc64 using CRQ based interface
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 2/8] tpm_backend: Implement check whether tpm backend is suspended Stefan Berger
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc; +Cc: marcandre.lureau, Stefan Berger, qemu-devel, david

Implement support for TPM on ppc64 by implementing the vTPM CRQ interface
as a frontend. It can use the tpm_emulator driver backend with the external
swtpm.

The Linux vTPM driver for ppc64 works with this emulation.

This TPM emulator also handles the TPM 2 case.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig
index 4c8ee87d67..66a570aac1 100644
--- a/hw/tpm/Kconfig
+++ b/hw/tpm/Kconfig
@@ -22,3 +22,9 @@ config TPM_EMULATOR
     bool
     default y
     depends on TPMDEV
+
+config TPM_SPAPR
+    bool
+    default n
+    select TPMDEV
+    depends on PSERIES
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index de0b85d02a..85eb99ae05 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -4,3 +4,4 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
 common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
 common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
+obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o
diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c
new file mode 100644
index 0000000000..c4a67e2403
--- /dev/null
+++ b/hw/tpm/tpm_spapr.c
@@ -0,0 +1,405 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtual TPM
+ *
+ * Copyright (c) 2015, 2017 IBM Corporation.
+ *
+ * Authors:
+ *    Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "tpm_util.h"
+
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+#include "trace.h"
+
+#define DEBUG_SPAPR 0
+
+#define VIO_SPAPR_VTPM(obj) \
+     OBJECT_CHECK(SPAPRvTPMState, (obj), TYPE_TPM_SPAPR)
+
+typedef struct VioCRQ {
+    uint8_t valid;  /* 0x80: cmd; 0xc0: init crq */
+                    /* 0x81-0x83: CRQ message response */
+    uint8_t msg;    /* see below */
+    uint16_t len;   /* len of TPM request; len of TPM response */
+    uint32_t data;  /* rtce_dma_handle when sending TPM request */
+    uint64_t reserved;
+} VioCRQ;
+
+typedef union TPMSpaprCRQ {
+    VioCRQ s;
+    uint8_t raw[sizeof(VioCRQ)];
+} TPMSpaprCRQ;
+
+#define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND  0xC0
+#define SPAPR_VTPM_VALID_COMMAND           0x80
+#define SPAPR_VTPM_MSG_RESULT              0x80
+
+/* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */
+#define SPAPR_VTPM_INIT_CRQ_RESULT           0x1
+#define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT  0x2
+
+/* msg types for valid = SPAPR_VTPM_VALID_CMD */
+#define SPAPR_VTPM_GET_VERSION               0x1
+#define SPAPR_VTPM_TPM_COMMAND               0x2
+#define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE      0x3
+#define SPAPR_VTPM_PREPARE_TO_SUSPEND        0x4
+
+/* response error messages */
+#define SPAPR_VTPM_VTPM_ERROR                0xff
+
+/* error codes */
+#define SPAPR_VTPM_ERR_COPY_IN_FAILED        0x3
+#define SPAPR_VTPM_ERR_COPY_OUT_FAILED       0x4
+
+#define MAX_BUFFER_SIZE TARGET_PAGE_SIZE
+
+typedef struct {
+    SpaprVioDevice vdev;
+
+    TPMSpaprCRQ crq; /* track single TPM command */
+
+    uint8_t state;
+#define SPAPR_VTPM_STATE_NONE         0
+#define SPAPR_VTPM_STATE_EXECUTION    1
+#define SPAPR_VTPM_STATE_COMPLETION   2
+
+    unsigned char buffer[MAX_BUFFER_SIZE];
+
+    TPMBackendCmd cmd;
+
+    TPMBackend *be_driver;
+    TPMVersion be_tpm_version;
+
+    size_t be_buffer_size;
+} SPAPRvTPMState;
+
+static void tpm_spapr_show_buffer(const unsigned char *buffer,
+                                  size_t buffer_size, const char *string)
+{
+    size_t len, i;
+    char *line_buffer, *p;
+
+    len = MIN(tpm_cmd_get_size(buffer), buffer_size);
+
+    /*
+     * allocate enough room for 3 chars per buffer entry plus a
+     * newline after every 16 chars and a final null terminator.
+     */
+    line_buffer = g_malloc(len * 3 + (len / 16) + 1);
+
+    for (i = 0, p = line_buffer; i < len; i++) {
+        if (i && !(i % 16)) {
+            p += sprintf(p, "\n");
+        }
+        p += sprintf(p, "%.2X ", buffer[i]);
+    }
+    trace_tpm_spapr_show_buffer(string, len, line_buffer);
+
+    g_free(line_buffer);
+}
+
+/*
+ * Send a request to the TPM.
+ */
+static void tpm_spapr_tpm_send(SPAPRvTPMState *s)
+{
+    if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
+        tpm_spapr_show_buffer(s->buffer, sizeof(s->buffer), "To TPM");
+    }
+
+    s->state = SPAPR_VTPM_STATE_EXECUTION;
+    s->cmd = (TPMBackendCmd) {
+        .locty = 0,
+        .in = s->buffer,
+        .in_len = MIN(tpm_cmd_get_size(s->buffer), sizeof(s->buffer)),
+        .out = s->buffer,
+        .out_len = sizeof(s->buffer),
+    };
+
+    tpm_backend_deliver_request(s->be_driver, &s->cmd);
+}
+
+static int tpm_spapr_process_cmd(SPAPRvTPMState *s, uint64_t dataptr)
+{
+    long rc;
+
+    /* a max. of be_buffer_size bytes can be transported */
+    rc = spapr_vio_dma_read(&s->vdev, dataptr,
+                            s->buffer, s->be_buffer_size);
+    if (rc) {
+        error_report("tpm_spapr_got_payload: DMA read failure");
+    }
+    /* let vTPM handle any malformed request */
+    tpm_spapr_tpm_send(s);
+
+    return rc;
+}
+
+static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM(dev);
+    TPMSpaprCRQ local_crq;
+    TPMSpaprCRQ *crq = &s->crq; /* requests only */
+    int rc;
+
+    memcpy(&local_crq.raw, crq_data, sizeof(local_crq.raw));
+
+    trace_tpm_spapr_do_crq(local_crq.raw[0], local_crq.raw[1]);
+
+    switch (local_crq.s.valid) {
+    case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */
+
+        /* Respond to initialization request */
+        switch (local_crq.s.msg) {
+        case SPAPR_VTPM_INIT_CRQ_RESULT:
+            trace_tpm_spapr_do_crq_crq_result();
+            memset(local_crq.raw, 0, sizeof(local_crq.raw));
+            local_crq.s.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
+            local_crq.s.msg = SPAPR_VTPM_INIT_CRQ_RESULT;
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+
+        case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT:
+            trace_tpm_spapr_do_crq_crq_complete_result();
+            memset(local_crq.raw, 0, sizeof(local_crq.raw));
+            local_crq.s.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
+            local_crq.s.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT;
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+        }
+
+        break;
+    case SPAPR_VTPM_VALID_COMMAND: /* Payloads */
+        switch (local_crq.s.msg) {
+        case SPAPR_VTPM_TPM_COMMAND:
+            trace_tpm_spapr_do_crq_tpm_command();
+            if (s->state == SPAPR_VTPM_STATE_EXECUTION) {
+                return H_BUSY;
+            }
+            /* this crq is tracked */
+            memcpy(crq->raw, crq_data, sizeof(crq->raw));
+
+            rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->s.data));
+
+            if (rc == H_SUCCESS) {
+                crq->s.valid = be16_to_cpu(0);
+            } else {
+                local_crq.s.valid = SPAPR_VTPM_MSG_RESULT;
+                local_crq.s.msg = SPAPR_VTPM_VTPM_ERROR;
+                local_crq.s.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED);
+                spapr_vio_send_crq(dev, local_crq.raw);
+            }
+            break;
+
+        case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE:
+            trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size);
+            local_crq.s.msg |= SPAPR_VTPM_MSG_RESULT;
+            local_crq.s.len = cpu_to_be16(s->be_buffer_size);
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+
+        case SPAPR_VTPM_GET_VERSION:
+            local_crq.s.msg |= SPAPR_VTPM_MSG_RESULT;
+            local_crq.s.len = cpu_to_be16(0);
+            switch (s->be_tpm_version) {
+            case TPM_VERSION_UNSPEC:
+                local_crq.s.data = cpu_to_be32(0);
+                break;
+            case TPM_VERSION_1_2:
+                local_crq.s.data = cpu_to_be32(1);
+                break;
+            case TPM_VERSION_2_0:
+                local_crq.s.data = cpu_to_be32(2);
+                break;
+            }
+            trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.s.data));
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+
+        case SPAPR_VTPM_PREPARE_TO_SUSPEND:
+            trace_tpm_spapr_do_crq_prepare_to_suspend();
+            local_crq.s.msg |= SPAPR_VTPM_MSG_RESULT;
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+
+        default:
+            trace_tpm_spapr_do_crq_unknown_msg_type(crq->s.msg);
+        }
+        break;
+    default:
+        trace_tpm_spapr_do_crq_unknown_crq(local_crq.raw[0], local_crq.raw[1]);
+    };
+
+    return H_SUCCESS;
+}
+
+static void tpm_spapr_request_completed(TPMIf *ti, int ret)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM(ti);
+    TPMSpaprCRQ *crq = &s->crq;
+    uint32_t len;
+    int rc;
+
+    s->state = SPAPR_VTPM_STATE_COMPLETION;
+
+    /* a max. of be_buffer_size bytes can be transported */
+    len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size);
+    rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->s.data),
+                             s->buffer, len);
+
+    if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
+        tpm_spapr_show_buffer(s->buffer, len, "From TPM");
+    }
+
+    crq->s.valid = SPAPR_VTPM_MSG_RESULT;
+    if (rc == H_SUCCESS) {
+        crq->s.msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT;
+        crq->s.len = cpu_to_be16(len);
+    } else {
+        error_report("%s: DMA write failure", __func__);
+        crq->s.msg = SPAPR_VTPM_VTPM_ERROR;
+        crq->s.len = cpu_to_be16(0);
+        crq->s.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED);
+    }
+
+    rc = spapr_vio_send_crq(&s->vdev, crq->raw);
+    if (rc) {
+        error_report("%s: Error sending response", __func__);
+    }
+}
+
+static int tpm_spapr_do_startup_tpm(SPAPRvTPMState *s, size_t buffersize)
+{
+    return tpm_backend_startup_tpm(s->be_driver, buffersize);
+}
+
+static void tpm_spapr_update_deviceclass(SpaprVioDevice *dev)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM(dev);
+    SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+
+    switch (s->be_tpm_version) {
+    case TPM_VERSION_UNSPEC:
+        assert(false);
+        break;
+    case TPM_VERSION_1_2:
+        k->dt_name = "vtpm";
+        k->dt_type = "IBM,vtpm";
+        k->dt_compatible = "IBM,vtpm";
+        break;
+    case TPM_VERSION_2_0:
+        k->dt_name = "vtpm";
+        k->dt_type = "IBM,vtpm";
+        k->dt_compatible = "IBM,vtpm20";
+        break;
+    }
+}
+
+static void tpm_spapr_reset(SpaprVioDevice *dev)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM(dev);
+
+    s->state = SPAPR_VTPM_STATE_NONE;
+
+    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
+    tpm_spapr_update_deviceclass(dev);
+
+    s->be_buffer_size = MAX(ROUND_UP(tpm_backend_get_buffer_size(s->be_driver),
+                                     TARGET_PAGE_SIZE),
+                            sizeof(s->buffer));
+
+    tpm_backend_reset(s->be_driver);
+    tpm_spapr_do_startup_tpm(s, s->be_buffer_size);
+}
+
+static enum TPMVersion tpm_spapr_get_version(TPMIf *ti)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM(ti);
+
+    if (tpm_backend_had_startup_error(s->be_driver)) {
+        return TPM_VERSION_UNSPEC;
+    }
+
+    return tpm_backend_get_tpm_version(s->be_driver);
+}
+
+static const VMStateDescription vmstate_spapr_vtpm = {
+    .name = "tpm-spapr",
+    .unmigratable = 1,
+};
+
+static Property tpm_spapr_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(SPAPRvTPMState, vdev),
+    DEFINE_PROP_TPMBE("tpmdev", SPAPRvTPMState, be_driver),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM(dev);
+
+    if (!tpm_find()) {
+        error_setg(errp, "at most one TPM device is permitted");
+        return;
+    }
+
+    dev->crq.SendFunc = tpm_spapr_do_crq;
+
+    if (!s->be_driver) {
+        error_setg(errp, "'tpmdev' property is required");
+        return;
+    }
+}
+
+static void tpm_spapr_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+    TPMIfClass *tc = TPM_IF_CLASS(klass);
+
+    k->realize = tpm_spapr_realizefn;
+    k->reset = tpm_spapr_reset;
+    k->signal_mask = 0x00000001;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->props = tpm_spapr_properties;
+    k->rtce_window_size = 0x10000000;
+    dc->vmsd = &vmstate_spapr_vtpm;
+
+    tc->model = TPM_MODEL_TPM_SPAPR;
+    tc->get_version = tpm_spapr_get_version;
+    tc->request_completed = tpm_spapr_request_completed;
+}
+
+static const TypeInfo tpm_spapr_info = {
+    .name          = TYPE_TPM_SPAPR,
+    .parent        = TYPE_VIO_SPAPR_DEVICE,
+    .instance_size = sizeof(SPAPRvTPMState),
+    .class_init    = tpm_spapr_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_TPM_IF },
+        { }
+    }
+};
+
+static void tpm_spapr_register_types(void)
+{
+    type_register_static(&tpm_spapr_info);
+}
+
+type_init(tpm_spapr_register_types)
diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
index 89804bcd64..6278a39618 100644
--- a/hw/tpm/trace-events
+++ b/hw/tpm/trace-events
@@ -55,3 +55,15 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u"
 
 # tpm_ppi.c
 tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu"
+
+# hw/tpm/tpm_spapr.c
+tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s"
+tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x"
+tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT"
+tpm_spapr_do_crq_crq_complete_result(void) "SPAPR_VTPM_INIT_CRQ_COMP_RESULT"
+tpm_spapr_do_crq_tpm_command(void) "got TPM command payload"
+tpm_spapr_do_crq_tpm_get_rtce_buffer_size(size_t buffersize) "response: buffer size is %zu"
+tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u"
+tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend"
+tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x"
+tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..."
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index 5b541a71c8..15979a3647 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -45,11 +45,14 @@ typedef struct TPMIfClass {
 
 #define TYPE_TPM_TIS                "tpm-tis"
 #define TYPE_TPM_CRB                "tpm-crb"
+#define TYPE_TPM_SPAPR              "tpm-spapr"
 
 #define TPM_IS_TIS(chr)                             \
     object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS)
 #define TPM_IS_CRB(chr)                             \
     object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB)
+#define TPM_IS_SPAPR(chr)                           \
+    object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR)
 
 /* returns NULL unless there is exactly one TPM device */
 static inline TPMIf *tpm_find(void)
diff --git a/qapi/tpm.json b/qapi/tpm.json
index b30323bb6b..63878aa0f4 100644
--- a/qapi/tpm.json
+++ b/qapi/tpm.json
@@ -12,11 +12,11 @@
 #
 # @tpm-tis: TPM TIS model
 # @tpm-crb: TPM CRB model (since 2.12)
+# @tpm-spapr: TPM SPAPR model (since 5.0)
 #
 # Since: 1.5
 ##
-{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb' ] }
-
+{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb', 'tpm-spapr' ] }
 ##
 # @query-tpm-models:
 #
@@ -29,7 +29,7 @@
 # Example:
 #
 # -> { "execute": "query-tpm-models" }
-# <- { "return": [ "tpm-tis", "tpm-crb" ] }
+# <- { "return": [ "tpm-tis", "tpm-crb", "tpm-spapr" ] }
 #
 ##
 { 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 2/8] tpm_backend: Implement check whether tpm backend is suspended
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 1/8] tpm_spapr: Support TPM for ppc64 using CRQ based interface Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 3/8] tpm_emulator: Implement callback for whether we are suspended Stefan Berger
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc
  Cc: marcandre.lureau, Stefan Berger, Stefan Berger, qemu-devel, david

Some frontends need to know whether the backend is suspended.
Implement tpm_backend_is_suspended().

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

diff --git a/backends/tpm.c b/backends/tpm.c
index 375587e743..424c9fd485 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -163,6 +163,13 @@ size_t tpm_backend_get_buffer_size(TPMBackend *s)
     return k->get_buffer_size(s);
 }
 
+bool tpm_backend_is_suspended(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->is_suspended(s);
+}
+
 TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
 {
     TPMInfo *info = g_new0(TPMInfo, 1);
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 9e7451fb52..f5d8051b45 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -84,6 +84,8 @@ struct TPMBackendClass {
     TpmTypeOptions *(*get_tpm_options)(TPMBackend *t);
 
     void (*handle_request)(TPMBackend *s, TPMBackendCmd *cmd, Error **errp);
+
+    bool (*is_suspended)(TPMBackend *t);
 };
 
 /**
@@ -213,6 +215,16 @@ void tpm_backend_finish_sync(TPMBackend *s);
  */
 TPMInfo *tpm_backend_query_tpm(TPMBackend *s);
 
+/**
+ * tpm_backend_is_suspended:
+ * @s: the backend to call into
+ *
+ * Whether the backend is suspended
+ *
+ * Returns true in case the backend is suspended
+ */
+bool tpm_backend_is_suspended(TPMBackend *s);
+
 TPMBackend *qemu_find_tpm_be(const char *id);
 
 #endif
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 3/8] tpm_emulator: Implement callback for whether we are suspended
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 1/8] tpm_spapr: Support TPM for ppc64 using CRQ based interface Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 2/8] tpm_backend: Implement check whether tpm backend is suspended Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  2019-12-12 18:33   ` Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 4/8] tpm_passthrough: " Stefan Berger
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc
  Cc: marcandre.lureau, Stefan Berger, Stefan Berger, qemu-devel, david

Implement the check whether the emulator backend is suspended.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
index 22f9113432..7be7d3a91b 100644
--- a/hw/tpm/tpm_emulator.c
+++ b/hw/tpm/tpm_emulator.c
@@ -80,6 +80,8 @@ typedef struct TPMEmulator {
     unsigned int established_flag_cached:1;
 
     TPMBlobBuffers state_blobs;
+
+    bool is_suspended;
 } TPMEmulator;
 
 struct tpm_error {
@@ -486,6 +488,13 @@ static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
     return actual_size;
 }
 
+static bool tpm_emulator_is_suspended(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+    return tpm_emu->is_suspended;
+}
+
 static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
 {
     Error *err = NULL;
@@ -846,6 +855,8 @@ static int tpm_emulator_pre_save(void *opaque)
     TPMBackend *tb = opaque;
     TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 
+    tpm_emu->is_suspended = true;
+
     trace_tpm_emulator_pre_save();
 
     tpm_backend_finish_sync(tb);
@@ -975,6 +986,7 @@ static void tpm_emulator_class_init(ObjectClass *klass, void *data)
     tbc->get_tpm_version = tpm_emulator_get_tpm_version;
     tbc->get_buffer_size = tpm_emulator_get_buffer_size;
     tbc->get_tpm_options = tpm_emulator_get_tpm_options;
+    tbc->is_suspended = tpm_emulator_is_suspended;
 
     tbc->handle_request = tpm_emulator_handle_request;
 }
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 4/8] tpm_passthrough: Implement callback for whether we are suspended
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
                   ` (2 preceding siblings ...)
  2019-12-12 18:07 ` [PATCH v4 3/8] tpm_emulator: Implement callback for whether we are suspended Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 5/8] tpm: Return bool from tpm_backend_finish_sync Stefan Berger
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc
  Cc: marcandre.lureau, Stefan Berger, Stefan Berger, qemu-devel, david

Implement the callback for whether the passthrough backend is
suspended. We always respond with false.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index f67244b5d4..b759c7d30c 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -203,6 +203,11 @@ static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb)
     return tpm_pt->tpm_buffersize;
 }
 
+static bool tpm_passthrough_is_suspended(TPMBackend *tb)
+{
+    return false;
+}
+
 /*
  * Unless path or file descriptor set has been provided by user,
  * determine the sysfs cancel file following kernel documentation
@@ -386,6 +391,7 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
     tbc->get_buffer_size = tpm_passthrough_get_buffer_size;
     tbc->get_tpm_options = tpm_passthrough_get_tpm_options;
     tbc->handle_request = tpm_passthrough_handle_request;
+    tbc->is_suspended = tpm_passthrough_is_suspended;
 }
 
 static const TypeInfo tpm_passthrough_info = {
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 5/8] tpm: Return bool from tpm_backend_finish_sync
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
                   ` (3 preceding siblings ...)
  2019-12-12 18:07 ` [PATCH v4 4/8] tpm_passthrough: " Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 6/8] tpm_spapr: Support suspend and resume Stefan Berger
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc; +Cc: marcandre.lureau, Stefan Berger, qemu-devel, david

Return true in case we had to wait for an outstanding response
to come back, false otherwise.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

diff --git a/backends/tpm.c b/backends/tpm.c
index 424c9fd485..ae4d8c526b 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -49,11 +49,15 @@ static int tpm_backend_worker_thread(gpointer data)
     return 0;
 }
 
-void tpm_backend_finish_sync(TPMBackend *s)
+bool tpm_backend_finish_sync(TPMBackend *s)
 {
+    bool ret = s->cmd != NULL;
+
     while (s->cmd) {
         aio_poll(qemu_get_aio_context(), true);
     }
+
+    return ret;
 }
 
 enum TpmType tpm_backend_get_type(TPMBackend *s)
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index f5d8051b45..3ab9f51ba4 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -202,8 +202,10 @@ size_t tpm_backend_get_buffer_size(TPMBackend *s);
  *
  * Finish the pending command synchronously (this will call aio_poll()
  * on qemu main AIOContext until it ends)
+ *
+ * Returns true in case there was a pending command, false otherwise.
  */
-void tpm_backend_finish_sync(TPMBackend *s);
+bool tpm_backend_finish_sync(TPMBackend *s);
 
 /**
  * tpm_backend_query_tpm:
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 6/8] tpm_spapr: Support suspend and resume
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
                   ` (4 preceding siblings ...)
  2019-12-12 18:07 ` [PATCH v4 5/8] tpm: Return bool from tpm_backend_finish_sync Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 7/8] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES config Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 8/8] docs: tpm: Add example command line for ppc64 and tpm-spapr Stefan Berger
  7 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc; +Cc: marcandre.lureau, Stefan Berger, qemu-devel, david

Extend the tpm_spapr frontend with VM suspend and resume support.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c
index c4a67e2403..52e0405ab4 100644
--- a/hw/tpm/tpm_spapr.c
+++ b/hw/tpm/tpm_spapr.c
@@ -87,6 +87,8 @@ typedef struct {
     TPMVersion be_tpm_version;
 
     size_t be_buffer_size;
+
+    bool deliver_response; /* whether to deliver response after VM resume */
 } SPAPRvTPMState;
 
 static void tpm_spapr_show_buffer(const unsigned char *buffer,
@@ -255,6 +257,14 @@ static void tpm_spapr_request_completed(TPMIf *ti, int ret)
     TPMSpaprCRQ *crq = &s->crq;
     uint32_t len;
     int rc;
+    bool be_suspended;
+
+    be_suspended = tpm_backend_is_suspended(s->be_driver);
+    if (be_suspended) {
+        /* defer delivery of response until .post_load */
+        s->deliver_response |= true;
+        return;
+    }
 
     s->state = SPAPR_VTPM_STATE_COMPLETION;
 
@@ -316,6 +326,7 @@ static void tpm_spapr_reset(SpaprVioDevice *dev)
     SPAPRvTPMState *s = VIO_SPAPR_VTPM(dev);
 
     s->state = SPAPR_VTPM_STATE_NONE;
+    s->deliver_response = false;
 
     s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
     tpm_spapr_update_deviceclass(dev);
@@ -339,9 +350,53 @@ static enum TPMVersion tpm_spapr_get_version(TPMIf *ti)
     return tpm_backend_get_tpm_version(s->be_driver);
 }
 
+/* persistent state handling */
+
+static int tpm_spapr_pre_save(void *opaque)
+{
+    SPAPRvTPMState *s = opaque;
+
+    s->deliver_response |= tpm_backend_finish_sync(s->be_driver);
+
+    trace_tpm_spapr_pre_save(s->deliver_response);
+    /*
+     * we cannot deliver the results to the VM since DMA would touch VM memory
+     */
+
+    return 0;
+}
+
+static int tpm_spapr_post_load(void *opaque, int version_id)
+{
+    SPAPRvTPMState *s = opaque;
+
+    if (s->deliver_response) {
+        trace_tpm_spapr_post_load();
+        /* deliver the results to the VM via DMA */
+        tpm_spapr_request_completed(TPM_IF(s), 0);
+        s->deliver_response = false;
+    }
+
+    return 0;
+}
+
 static const VMStateDescription vmstate_spapr_vtpm = {
     .name = "tpm-spapr",
-    .unmigratable = 1,
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = tpm_spapr_pre_save,
+    .post_load = tpm_spapr_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_SPAPR_VIO(vdev, SPAPRvTPMState),
+
+        VMSTATE_UINT8(state, SPAPRvTPMState),
+        VMSTATE_BUFFER(buffer, SPAPRvTPMState),
+        /* remember DMA address */
+        VMSTATE_UINT32(crq.s.data, SPAPRvTPMState),
+        VMSTATE_BOOL(deliver_response, SPAPRvTPMState),
+        VMSTATE_END_OF_LIST(),
+    }
 };
 
 static Property tpm_spapr_properties[] = {
diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
index 6278a39618..d109661b96 100644
--- a/hw/tpm/trace-events
+++ b/hw/tpm/trace-events
@@ -67,3 +67,5 @@ tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u"
 tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend"
 tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x"
 tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..."
+tpm_spapr_pre_save(bool v) "TPM response to deliver after resume: %d"
+tpm_spapr_post_load(void) "Delivering TPM response after resume"
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 7/8] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES config
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
                   ` (5 preceding siblings ...)
  2019-12-12 18:07 ` [PATCH v4 6/8] tpm_spapr: Support suspend and resume Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  2019-12-12 18:07 ` [PATCH v4 8/8] docs: tpm: Add example command line for ppc64 and tpm-spapr Stefan Berger
  7 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc
  Cc: marcandre.lureau, Stefan Berger, Stefan Berger, qemu-devel, david

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index f927ec9c74..b5b3519158 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -10,6 +10,7 @@ config PSERIES
     select XICS_SPAPR
     select XIVE_SPAPR
     select MSI_NONBROKEN
+    select TPM_SPAPR
 
 config SPAPR_RNG
     bool
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 8/8] docs: tpm: Add example command line for ppc64 and tpm-spapr
  2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
                   ` (6 preceding siblings ...)
  2019-12-12 18:07 ` [PATCH v4 7/8] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES config Stefan Berger
@ 2019-12-12 18:07 ` Stefan Berger
  7 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:07 UTC (permalink / raw)
  To: qemu-ppc
  Cc: marcandre.lureau, Stefan Berger, Stefan Berger, qemu-devel, david

Add an example to the TPM docs for how to add a TPM SPAPR
device model to a QEMU VM emulating a pSeries machine.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
index 9c8cca042d..9c3e67d8a7 100644
--- a/docs/specs/tpm.txt
+++ b/docs/specs/tpm.txt
@@ -34,6 +34,12 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 -
 QEMU files related to TPM CRB interface:
  - hw/tpm/tpm_crb.c
 
+
+pSeries (ppc64) machines offer a tpm-spapr device model.
+
+QEMU files related to the SPAPR interface:
+ - hw/tpm/tpm_spapr.c
+
 = fw_cfg interface =
 
 The bios/firmware may read the "etc/tpm/config" fw_cfg entry for
@@ -281,7 +287,7 @@ swtpm socket --tpmstate dir=/tmp/mytpm1 \
   --log level=20
 
 Command line to start QEMU with the TPM emulator device communicating with
-the swtpm:
+the swtpm (x86):
 
 qemu-system-x86_64 -display sdl -accel kvm \
   -m 1024 -boot d -bios bios-256k.bin -boot menu=on \
@@ -289,6 +295,18 @@ qemu-system-x86_64 -display sdl -accel kvm \
   -tpmdev emulator,id=tpm0,chardev=chrtpm \
   -device tpm-tis,tpmdev=tpm0 test.img
 
+In case a pSeries machine is emulated, use the following command line:
+
+qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \
+  -m 1024 -bios slof.bin -boot menu=on \
+  -nodefaults -device VGA -device pci-ohci -device usb-kbd \
+  -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \
+  -tpmdev emulator,id=tpm0,chardev=chrtpm \
+  -device tpm-spapr,tpmdev=tpm0 \
+  -device spapr-vscsi,id=scsi0,reg=0x00002000 \
+  -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \
+  -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0
+
 
 In case SeaBIOS is used as firmware, it should show the TPM menu item
 after entering the menu with 'ESC'.
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 3/8] tpm_emulator: Implement callback for whether we are suspended
  2019-12-12 18:07 ` [PATCH v4 3/8] tpm_emulator: Implement callback for whether we are suspended Stefan Berger
@ 2019-12-12 18:33   ` Stefan Berger
  2019-12-12 20:10     ` Stefan Berger
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 18:33 UTC (permalink / raw)
  To: Stefan Berger, qemu-ppc; +Cc: marcandre.lureau, qemu-devel, david

On 12/12/19 1:07 PM, Stefan Berger wrote:
> Implement the check whether the emulator backend is suspended.
>
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>
> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
> index 22f9113432..7be7d3a91b 100644
> --- a/hw/tpm/tpm_emulator.c
> +++ b/hw/tpm/tpm_emulator.c
> @@ -80,6 +80,8 @@ typedef struct TPMEmulator {
>       unsigned int established_flag_cached:1;
>   
>       TPMBlobBuffers state_blobs;
> +
> +    bool is_suspended;
>   } TPMEmulator;
>   
>   struct tpm_error {
> @@ -486,6 +488,13 @@ static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
>       return actual_size;
>   }
>   
> +static bool tpm_emulator_is_suspended(TPMBackend *tb)
> +{
> +    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
> +
> +    return tpm_emu->is_suspended;
> +}
> +
>   static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
>   {
>       Error *err = NULL;
> @@ -846,6 +855,8 @@ static int tpm_emulator_pre_save(void *opaque)
>       TPMBackend *tb = opaque;
>       TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
>   
> +    tpm_emu->is_suspended = true;

This is the most critical part here. It must be true when we receive a 
response in the tpm_spapr_request_completed(). The problem is that what 
tpm_backend_finish_sync() does is not specific to this backend but more 
a global operation that another device could run as well -- none seem to 
do this today. So the point is that there could be a race here. This 
flag should really be set in '.pre_pre_save,' so before any other device 
could poll. Better would be calling a global function that indicates 
whether device suspension has started. In this case we could do away 
with this and just call that function from the spapr device.




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 3/8] tpm_emulator: Implement callback for whether we are suspended
  2019-12-12 18:33   ` Stefan Berger
@ 2019-12-12 20:10     ` Stefan Berger
  0 siblings, 0 replies; 11+ messages in thread
From: Stefan Berger @ 2019-12-12 20:10 UTC (permalink / raw)
  To: Stefan Berger, qemu-ppc; +Cc: marcandre.lureau, qemu-devel, david

On 12/12/19 1:33 PM, Stefan Berger wrote:
> On 12/12/19 1:07 PM, Stefan Berger wrote:
>> Implement the check whether the emulator backend is suspended.
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>>
>> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
>> index 22f9113432..7be7d3a91b 100644
>> --- a/hw/tpm/tpm_emulator.c
>> +++ b/hw/tpm/tpm_emulator.c
>> @@ -80,6 +80,8 @@ typedef struct TPMEmulator {
>>       unsigned int established_flag_cached:1;
>>         TPMBlobBuffers state_blobs;
>> +
>> +    bool is_suspended;
>>   } TPMEmulator;
>>     struct tpm_error {
>> @@ -486,6 +488,13 @@ static size_t 
>> tpm_emulator_get_buffer_size(TPMBackend *tb)
>>       return actual_size;
>>   }
>>   +static bool tpm_emulator_is_suspended(TPMBackend *tb)
>> +{
>> +    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
>> +
>> +    return tpm_emu->is_suspended;
>> +}
>> +
>>   static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
>>   {
>>       Error *err = NULL;
>> @@ -846,6 +855,8 @@ static int tpm_emulator_pre_save(void *opaque)
>>       TPMBackend *tb = opaque;
>>       TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
>>   +    tpm_emu->is_suspended = true;
>
> This is the most critical part here. It must be true when we receive a 
> response in the tpm_spapr_request_completed(). The problem is that 
> what tpm_backend_finish_sync() does is not specific to this backend 
> but more a global operation that another device could run as well -- 
> none seem to do this today. So the point is that there could be a race 
> here. This flag should really be set in '.pre_pre_save,' so before any 
> other device could poll. Better would be calling a global function 
> that indicates whether device suspension has started. In this case we 
> could do away with this and just call that function from the spapr 
> device.


runstate_check(RUN_STATE_FINISH_MIGRATE) seems to be what we need here...



>
>
>



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2019-12-12 20:12 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-12 18:07 [PATCH v4 0/8] Add vTPM emulator supportfor ppc64 platform Stefan Berger
2019-12-12 18:07 ` [PATCH v4 1/8] tpm_spapr: Support TPM for ppc64 using CRQ based interface Stefan Berger
2019-12-12 18:07 ` [PATCH v4 2/8] tpm_backend: Implement check whether tpm backend is suspended Stefan Berger
2019-12-12 18:07 ` [PATCH v4 3/8] tpm_emulator: Implement callback for whether we are suspended Stefan Berger
2019-12-12 18:33   ` Stefan Berger
2019-12-12 20:10     ` Stefan Berger
2019-12-12 18:07 ` [PATCH v4 4/8] tpm_passthrough: " Stefan Berger
2019-12-12 18:07 ` [PATCH v4 5/8] tpm: Return bool from tpm_backend_finish_sync Stefan Berger
2019-12-12 18:07 ` [PATCH v4 6/8] tpm_spapr: Support suspend and resume Stefan Berger
2019-12-12 18:07 ` [PATCH v4 7/8] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES config Stefan Berger
2019-12-12 18:07 ` [PATCH v4 8/8] docs: tpm: Add example command line for ppc64 and tpm-spapr Stefan Berger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).