qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/3] Add TPM support to ppc64
@ 2016-01-04 16:14 Stefan Berger
  2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 1/3] Enable PPC64 with TPM support Stefan Berger
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Stefan Berger @ 2016-01-04 16:14 UTC (permalink / raw)
  To: qemu-ppc; +Cc: thuth, aik, nikunj, agraf, qemu-devel, jb613w, Stefan Berger

The following series of patches adds TPM support for ppc64.
The CUSE TPM backend, which is part of the TPM passthrough backend, 
should be considered for providing a private vTPM to a VM. The
series implementing support for this has been posted here:

http://lists.gnu.org/archive/html/qemu-devel/2016-01/msg00086.html

Stefan Berger (3):
  Enable PPC64 with TPM support
  tpm: remove TPMState usage from backend
  tpm: Support TPM for ppc64 using CRQ based interface

 backends/tpm.c               |   5 +-
 configure                    |   3 +-
 hw/tpm/Makefile.objs         |   2 +
 hw/tpm/spapr_vtpm.c          | 541 +++++++++++++++++++++++++++++++++++++++++++
 hw/tpm/spapr_vtpm.h          |  65 ++++++
 hw/tpm/tpm_passthrough.c     |  18 +-
 hw/tpm/tpm_tis.c             |   7 +-
 include/hw/ppc/spapr_vio.h   |   1 +
 include/sysemu/tpm.h         |   1 +
 include/sysemu/tpm_backend.h |  15 +-
 qapi-schema.json             |   6 +-
 11 files changed, 648 insertions(+), 16 deletions(-)
 create mode 100644 hw/tpm/spapr_vtpm.c
 create mode 100644 hw/tpm/spapr_vtpm.h

-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 1/3] Enable PPC64 with TPM support
  2016-01-04 16:14 [Qemu-devel] [PATCH v2 0/3] Add TPM support to ppc64 Stefan Berger
@ 2016-01-04 16:14 ` Stefan Berger
  2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 2/3] tpm: remove TPMState usage from backend Stefan Berger
  2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 3/3] tpm: Support TPM for ppc64 using CRQ based interface Stefan Berger
  2 siblings, 0 replies; 4+ messages in thread
From: Stefan Berger @ 2016-01-04 16:14 UTC (permalink / raw)
  To: qemu-ppc; +Cc: thuth, aik, nikunj, Stefan Berger, agraf, qemu-devel, jb613w

From: Stefan Berger <stefanb@linux.vnet.ibm.com>

Compile the TPM passthrough device emulation on ppc64.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
CC: Alexander Graf <agraf@suse.de>
CC: qemu-ppc@nongnu.org
---
 configure | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/configure b/configure
index 83b40fc..82ca1b5 100755
--- a/configure
+++ b/configure
@@ -3229,7 +3229,8 @@ fi
 ##########################################
 # TPM passthrough is only on x86 Linux
 
-if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64; then
+if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64 \
+    -o "$cpu" = ppc64; then
   tpm_passthrough=$tpm
 else
   tpm_passthrough=no
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 2/3] tpm: remove TPMState usage from backend
  2016-01-04 16:14 [Qemu-devel] [PATCH v2 0/3] Add TPM support to ppc64 Stefan Berger
  2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 1/3] Enable PPC64 with TPM support Stefan Berger
@ 2016-01-04 16:14 ` Stefan Berger
  2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 3/3] tpm: Support TPM for ppc64 using CRQ based interface Stefan Berger
  2 siblings, 0 replies; 4+ messages in thread
From: Stefan Berger @ 2016-01-04 16:14 UTC (permalink / raw)
  To: qemu-ppc; +Cc: thuth, aik, nikunj, Stefan Berger, agraf, qemu-devel, jb613w

From: Stefan Berger <stefanb@linux.vnet.ibm.com>

Remove the direct TPMState usage from the TPM backend. This allows different
frontends to use the backend. A few more parameters now need to be passed to the
backend.

Other frontends may need different TPMState structures if for example
the device types they are using are not always visible during compilation.
An example is the usage of the PPC64 specific VIOsPAPRDevice whose
include files are not all visible to x86 target for example. Therefore,
we now pass void * where previously TPMState * was passed.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 backends/tpm.c               |  5 +++--
 hw/tpm/tpm_passthrough.c     | 18 ++++++++++++------
 hw/tpm/tpm_tis.c             |  7 +++++--
 include/sysemu/tpm_backend.h | 15 +++++++++++----
 4 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/backends/tpm.c b/backends/tpm.c
index a512693..33af8a1 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -39,12 +39,13 @@ void tpm_backend_destroy(TPMBackend *s)
     k->ops->destroy(s);
 }
 
-int tpm_backend_init(TPMBackend *s, TPMState *state,
+int tpm_backend_init(TPMBackend *s, void *state,
+                     uint8_t *locty_number, TPMLocality **locty_data,
                      TPMRecvDataCB *datacb)
 {
     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 
-    return k->ops->init(s, state, datacb);
+    return k->ops->init(s, state, locty_number, locty_data, datacb);
 }
 
 int tpm_backend_startup_tpm(TPMBackend *s)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index cef3696..50ef15c 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -54,7 +54,10 @@ static const VMStateDescription vmstate_tpm_cuse;
 
 /* data structures */
 typedef struct TPMPassthruThreadParams {
-    TPMState *tpm_state;
+    void *tpm_state;
+
+    uint8_t *locty_number;
+    TPMLocality **locty_data;
 
     TPMRecvDataCB *recv_data_callback;
     TPMBackend *tb;
@@ -252,12 +255,12 @@ static void tpm_passthrough_worker_thread(gpointer data,
     switch (cmd) {
     case TPM_BACKEND_CMD_PROCESS_CMD:
         tpm_passthrough_unix_transfer(tpm_pt,
-                                      thr_parms->tpm_state->locty_number,
-                                      thr_parms->tpm_state->locty_data,
+                                      *thr_parms->locty_number,
+                                      *thr_parms->locty_data,
                                       &selftest_done);
 
         thr_parms->recv_data_callback(thr_parms->tpm_state,
-                                      thr_parms->tpm_state->locty_number,
+                                      *thr_parms->locty_number,
                                       selftest_done);
         /* result delivered */
         qemu_mutex_lock(&tpm_pt->state_lock);
@@ -400,12 +403,15 @@ static void tpm_passthrough_reset(TPMBackend *tb)
     tpm_pt->tpm_busy = false;
 }
 
-static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
+static int tpm_passthrough_init(TPMBackend *tb, void *tpm_state,
+                                uint8_t *locty_number, TPMLocality **locty_data,
                                 TPMRecvDataCB *recv_data_cb)
 {
     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
 
-    tpm_pt->tpm_thread_params.tpm_state = s;
+    tpm_pt->tpm_thread_params.tpm_state = tpm_state;
+    tpm_pt->tpm_thread_params.locty_number = locty_number;
+    tpm_pt->tpm_thread_params.locty_data = locty_data;
     tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
     tpm_pt->tpm_thread_params.tb = tb;
 
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index 61b26d1..3b69af4 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -395,9 +395,10 @@ static void tpm_tis_receive_bh(void *opaque)
 /*
  * Callback from the TPM to indicate that the response was received.
  */
-static void tpm_tis_receive_cb(TPMState *s, uint8_t locty,
+static void tpm_tis_receive_cb(void *opaque, uint8_t locty,
                                bool is_selftest_done)
 {
+    TPMState *s = opaque;
     TPMTISEmuState *tis = &s->s.tis;
     uint8_t l;
 
@@ -1189,7 +1190,9 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
 
     s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
 
-    if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
+    if (tpm_backend_init(s->be_driver, s,
+                         &s->locty_number, &s->locty_data,
+                         tpm_tis_receive_cb)) {
         error_setg(errp, "tpm_tis: backend driver with id %s could not be "
                    "initialized", s->backend);
         return;
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 92bc3e4..927254a 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -33,6 +33,8 @@ typedef struct TPMBackend TPMBackend;
 
 typedef struct TPMDriverOps TPMDriverOps;
 
+typedef struct TPMLocality TPMLocality;
+
 struct TPMBackendClass {
     ObjectClass parent_class;
 
@@ -56,7 +58,7 @@ struct TPMBackend {
     QLIST_ENTRY(TPMBackend) list;
 };
 
-typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty, bool selftest_done);
+typedef void (TPMRecvDataCB)(void *, uint8_t locty, bool selftest_done);
 
 typedef struct TPMSizedBuffer {
     uint32_t size;
@@ -85,7 +87,9 @@ struct TPMDriverOps {
     void (*destroy)(TPMBackend *t);
 
     /* initialize the backend */
-    int (*init)(TPMBackend *t, TPMState *s, TPMRecvDataCB *datacb);
+    int (*init)(TPMBackend *t, void *tpm_state,
+                uint8_t *locty_number, TPMLocality **locty_data,
+                TPMRecvDataCB *datacb);
     /* start up the TPM on the backend */
     int (*startup_tpm)(TPMBackend *t);
     /* returns true if nothing will ever answer TPM requests */
@@ -132,14 +136,17 @@ void tpm_backend_destroy(TPMBackend *s);
 /**
  * tpm_backend_init:
  * @s: the backend to initialized
- * @state: TPMState
+ * @state: opaque pointer to TPM state
+ * @locty_number: pointer to locality_number
+ * @locty_data: pointer to locality_data pointer
  * @datacb: callback for sending data to frontend
  *
  * Initialize the backend with the given variables.
  *
  * Returns 0 on success.
  */
-int tpm_backend_init(TPMBackend *s, TPMState *state,
+int tpm_backend_init(TPMBackend *s, void *state,
+                     uint8_t *locty_number, TPMLocality **locty_data,
                      TPMRecvDataCB *datacb);
 
 /**
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 3/3] tpm: Support TPM for ppc64 using CRQ based interface
  2016-01-04 16:14 [Qemu-devel] [PATCH v2 0/3] Add TPM support to ppc64 Stefan Berger
  2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 1/3] Enable PPC64 with TPM support Stefan Berger
  2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 2/3] tpm: remove TPMState usage from backend Stefan Berger
@ 2016-01-04 16:14 ` Stefan Berger
  2 siblings, 0 replies; 4+ messages in thread
From: Stefan Berger @ 2016-01-04 16:14 UTC (permalink / raw)
  To: qemu-ppc; +Cc: thuth, aik, nikunj, Stefan Berger, agraf, qemu-devel, jb613w

From: Stefan Berger <stefanb@linux.vnet.ibm.com>

Implement support for TPM on ppc64 by implementing the vTPM CRQ
interface (following PAPR) as a frontend.

Have the frontend call the existing passthrough TPM device backend
using data structures from the TPM TIS hardware interface emulation
(tpm_tis.c). The TIS implements a superset of functionality and the
vTPM CRQ interface uses part of it, such as only 1 of the 5 localities.

The Linux vTPM driver for ppc64 works with this emulation.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 hw/tpm/Makefile.objs       |   2 +
 hw/tpm/spapr_vtpm.c        | 541 +++++++++++++++++++++++++++++++++++++++++++++
 hw/tpm/spapr_vtpm.h        |  65 ++++++
 include/hw/ppc/spapr_vio.h |   1 +
 include/sysemu/tpm.h       |   1 +
 qapi-schema.json           |   6 +-
 6 files changed, 615 insertions(+), 1 deletion(-)
 create mode 100644 hw/tpm/spapr_vtpm.c
 create mode 100644 hw/tpm/spapr_vtpm.h

diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 64cecc3..f40f31d 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,2 +1,4 @@
 common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
+
+obj-$(CONFIG_PSERIES) += spapr_vtpm.o
diff --git a/hw/tpm/spapr_vtpm.c b/hw/tpm/spapr_vtpm.c
new file mode 100644
index 0000000..2560a9b
--- /dev/null
+++ b/hw/tpm/spapr_vtpm.c
@@ -0,0 +1,541 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtual TPM, aka ibmvtpm
+ *
+ * Parts based on spapr_vscsi.c
+ * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * Parts based on tpm_tis.c
+ * Copyright (C) 2006,2010-2013 IBM Corporation
+ *
+ * Copyright (c) 2015 IBM Corporation.
+ *
+ * Authors:
+ *    Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+/*
+ * For communication with the backend we are using the data structures used
+ * by the TPM TIS implementation (tpm_tis.c), which provides a superset of
+ * functionality with up to 5 localities. We always use locality = 0 and
+ * reuse the buffer to transfer the TPM command packets to the backend and
+ * receive TPM responses from the backend.
+ */
+
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "qemu/main-loop.h"
+#include "sysemu/tpm_backend.h"
+
+#include "spapr_vtpm.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define DEBUG_SPAPR_VTPM 0
+
+#define DPRINTF(fmt, ...) do { \
+    if (DEBUG_SPAPR_VTPM) { \
+        printf("QEMU-vTPM:" fmt, ## __VA_ARGS__); \
+    } \
+} while (0);
+
+
+#define TYPE_VIO_SPAPR_VTPM_DEVICE "spapr-vtpm"
+#define VIO_SPAPR_VTPM_DEVICE(obj) \
+     OBJECT_CHECK(SPAPRvTPMState, (obj), TYPE_VIO_SPAPR_VTPM_DEVICE)
+
+typedef struct {
+    VIOsPAPRDevice vdev;
+
+    spapr_vtpm_crq crq; /* track single TPM command */
+
+    union {
+        /*
+         * The backends expect TIS related data structures;
+         * we reuse it but only use locality 0.
+         */
+        TPMTISEmuState tis;
+    } s;
+
+    uint8_t     locty_number;
+    TPMLocality *locty_data;
+
+    char *backend;
+    TPMBackend *be_driver;
+    TPMVersion be_tpm_version;
+
+    QemuMutex state_lock;
+    QemuCond cmd_complete;
+} SPAPRvTPMState;
+
+/* Only use 1 locality (locality 0) */
+#define SPAPR_VTPM_NUM_LOCALITIES 1
+
+static uint32_t spapr_vtpm_get_size_from_buffer(const TPMSizedBuffer *sb)
+{
+    return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
+}
+
+static void spapr_vtpm_show_buffer(const TPMSizedBuffer *sb, const char *string)
+{
+#if DEBUG_SPAPR_VTPM
+    uint32_t len, i;
+
+    len = spapr_vtpm_get_size_from_buffer(sb);
+    printf("spapr_vtpm: %s length = %d\n", string, len);
+    for (i = 0; i < len; i++) {
+        if (i && !(i % 16)) {
+            printf("\n");
+        }
+        printf("%.2X ", sb->buffer[i]);
+    }
+    printf("\n");
+#endif
+}
+
+/*
+ * Send a request to the TPM.
+ */
+static void spapr_vtpm_tpm_send(SPAPRvTPMState *s, uint8_t locty)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+
+    spapr_vtpm_show_buffer(&tis->loc[locty].w_buffer, "spapr_vtpm: Tx TPM");
+
+    s->locty_number = locty;
+    s->locty_data = &tis->loc[locty];
+
+    /*
+     * w_offset serves as length indicator for length of data;
+     * it's reset when the response comes back.
+     * Since we copy the data via DMA, we need to set it here explicitly.
+     */
+    tis->loc[locty].w_offset =
+        spapr_vtpm_get_size_from_buffer(&tis->loc[locty].w_buffer);
+
+    tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
+
+    tpm_backend_deliver_request(s->be_driver);
+}
+
+static void spapr_vtpm_got_payload(SPAPRvTPMState *s, spapr_vtpm_crq *crq)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+    uint8_t locty = 0;
+
+    DPRINTF("vtpm_got_payload: crq->s.data = 0x%x  crq->s.len = %d\n",
+            crq->s.data, crq->s.len);
+    /* XXX Handle failure differently ? */
+    if (spapr_vio_dma_read(&s->vdev, crq->s.data,
+                           tis->loc[locty].w_buffer.buffer,
+                           tis->loc[locty].w_buffer.size)) {
+        fprintf(stderr, "vtpm_got_payload: DMA read failure !\n");
+        return;
+    }
+
+    /* let vTPM handle any malformed request */
+    spapr_vtpm_tpm_send(s, locty);
+}
+
+static int spapr_vtpm_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM_DEVICE(dev);
+    TPMTISEmuState *tis = &s->s.tis;
+    uint8_t locty = 0;
+    spapr_vtpm_crq local_crq;
+    spapr_vtpm_crq *crq = &s->crq; /* use for TPM requests only */
+
+    memcpy(&local_crq.raw, crq_data, sizeof(local_crq.raw));
+
+    DPRINTF("VTPM: do_crq %02x %02x ...\n",
+            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:
+            DPRINTF("vtpm_do_crq: SPAPR_VTPM_INIT_CRQ_RESULT\n");
+            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:
+            DPRINTF("vtpm_do_crq: SPAPR_VTPM_INIT_CRQ_COMP_RESULT\n");
+            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:
+            DPRINTF("vtpm_do_crq: got TPM command payload!\n");
+            if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION)
+                return H_BUSY;
+            /* this crq is tracked */
+            memcpy(crq->raw, crq_data, sizeof(crq->raw));
+            crq->s.valid = be16_to_cpu(0);
+            crq->s.len = be16_to_cpu(crq->s.len);
+            crq->s.data = be32_to_cpu(crq->s.data);
+            spapr_vtpm_got_payload(s, crq);
+            break;
+
+        case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE:
+            DPRINTF("vtpm_do_crq: resp: buffer size is %u\n",
+                    tis->loc[locty].w_buffer.size);
+            local_crq.s.msg |= SPAPR_VTPM_MSG_RESULT;
+            local_crq.s.len = cpu_to_be16(tis->loc[locty].w_buffer.size);
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+
+        case SPAPR_VTPM_GET_VERSION:
+            DPRINTF("vtpm_do_crq: resp: version 1\n");
+            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;
+            }
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+
+        case SPAPR_VTPM_PREPARE_TO_SUSPEND:
+            DPRINTF("vtpm_do_crq: resp: prep to suspend\n");
+            local_crq.s.msg |= SPAPR_VTPM_MSG_RESULT;
+            spapr_vio_send_crq(dev, local_crq.raw);
+            break;
+
+        default:
+            fprintf(stderr, "vtpm_do_crq: Unknown message type %02x\n",
+                    crq->s.msg);
+        }
+        break;
+    default:
+        fprintf(stderr, "vtpm_do_crq: unknown CRQ %02x %02x ...\n",
+                local_crq.raw[0], local_crq.raw[1]);
+    };
+
+    return 0;
+}
+
+static void spapr_vtpm_receive_bh(void *opaque)
+{
+    SPAPRvTPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+    spapr_vtpm_crq *crq = &s->crq;
+    uint8_t locty = 0;
+    uint32_t len;
+    int rc;
+
+    tis->bh_scheduled = false;
+
+    qemu_mutex_lock(&s->state_lock);
+
+    tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
+    tis->loc[locty].r_offset = 0;
+    tis->loc[locty].w_offset = 0;
+
+    len = spapr_vtpm_get_size_from_buffer(&tis->loc[locty].r_buffer);
+
+    spapr_vtpm_show_buffer(&tis->loc[locty].r_buffer, "spapr_vtpm: rx TPM");
+
+    DPRINTF("dma_write to crq->s.data = 0x%x\n", crq->s.data);
+    rc = spapr_vio_dma_write(&s->vdev, crq->s.data,
+                             tis->loc[locty].r_buffer.buffer,
+                             MIN(len, tis->loc[locty].r_buffer.size));
+
+    crq->s.valid = SPAPR_VTPM_MSG_RESULT;
+    crq->s.msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT;
+    crq->s.len = cpu_to_be16(len);
+    crq->s.data = cpu_to_be32(crq->s.data);
+
+    if (rc == 0) {
+        rc = spapr_vio_send_crq(&s->vdev, crq->raw);
+        if (rc) {
+            fprintf(stderr, "spapr_vtpm_receive_bh: Error sending response\n");
+        }
+    } else {
+        fprintf(stderr, "spapr_vtpm_receive_bh: Error with DMA write\n");
+    }
+
+    /* notify of completed command */
+    qemu_cond_signal(&s->cmd_complete);
+    qemu_mutex_unlock(&s->state_lock);
+}
+
+/*
+ * Callback from the TPM to indicate that the response was received.
+ */
+static void spapr_vtpm_receive_cb(void *opaque, uint8_t locty,
+                                  bool is_selftest_done)
+{
+    SPAPRvTPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+
+    qemu_mutex_lock(&s->state_lock);
+    /* notify of completed command */
+    qemu_cond_signal(&s->cmd_complete);
+    qemu_mutex_unlock(&s->state_lock);
+
+    qemu_bh_schedule(tis->bh);
+
+    tis->bh_scheduled = true;
+}
+
+static int spapr_vtpm_do_startup_tpm(SPAPRvTPMState *s)
+{
+    return tpm_backend_startup_tpm(s->be_driver);
+}
+
+/*
+ * Get the TPMVersion of the backend device being used
+ */
+TPMVersion spapr_vtpm_get_tpm_version(Object *obj)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM_DEVICE(obj);
+
+    return tpm_backend_get_tpm_version(s->be_driver);
+}
+
+static void spapr_vtpm_reset(VIOsPAPRDevice *dev)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM_DEVICE(dev);
+    TPMTISEmuState *tis = &s->s.tis;
+    int c;
+
+    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
+
+    tpm_backend_reset(s->be_driver);
+
+    for (c = 0; c < SPAPR_VTPM_NUM_LOCALITIES; c++) {
+        tis->loc[c].w_offset = 0;
+        tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
+        tis->loc[c].r_offset = 0;
+        tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
+    }
+
+    spapr_vtpm_do_startup_tpm(s);
+}
+
+void spapr_vtpm_create(VIOsPAPRBus *bus)
+{
+    DeviceState *dev;
+
+    DPRINTF("%s\n", __func__);
+
+    dev = qdev_create(&bus->bus, "spapr-vtpm");
+
+    qdev_init_nofail(dev);
+}
+
+/* persistent state handling */
+
+static void spapr_vtpm_pre_save(void *opaque)
+{
+    TPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+    uint8_t locty = 0;
+
+    DPRINTF("vtpm: suspend: locty = %d : r_offset = %d, w_offset = %d\n",
+            locty, tis->loc[0].r_offset, tis->loc[0].w_offset);
+
+    qemu_mutex_lock(&s->state_lock);
+
+    /* wait for outstanding request to complete */
+    if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
+        /*
+         * If we get here when the bh is scheduled but did not run,
+         * we won't get notified...
+         */
+        if (!tis->bh_scheduled) {
+            /* backend thread to notify us */
+            qemu_cond_wait(&s->cmd_complete, &s->state_lock);
+        }
+        if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
+            /* bottom half did not run - run its function */
+            qemu_mutex_unlock(&s->state_lock);
+            spapr_vtpm_receive_bh(opaque);
+            qemu_mutex_lock(&s->state_lock);
+        }
+    }
+
+    qemu_mutex_unlock(&s->state_lock);
+
+    /*
+     * requests are immediately sent to the backend, so we only ever
+     * have a buffer with TPM response data.
+     */
+    switch (tis->loc[locty].state) {
+    case TPM_TIS_STATE_COMPLETION:
+        memcpy(tis->buf,
+               tis->loc[locty].r_buffer.buffer,
+               MIN(sizeof(tis->buf),
+                   tis->loc[locty].r_buffer.size));
+    break;
+    default:
+        /* leak nothing */
+        memset(tis->buf, 0, sizeof(tis->buf));
+    break;
+    }
+}
+
+static int spapr_vtpm_post_load(void *opaque,
+                                int version_id __attribute__((unused)))
+{
+    TPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+    uint8_t locty = 0;
+
+    switch (tis->loc[locty].state) {
+    case TPM_TIS_STATE_COMPLETION:
+        memcpy(tis->loc[locty].r_buffer.buffer,
+               tis->buf,
+               MIN(sizeof(tis->buf),
+                   tis->loc[locty].r_buffer.size));
+    break;
+    default:
+    break;
+    }
+
+    DPRINTF("tpm_tis: resume : locty = %d : r_offset = %d, w_offset = %d\n",
+            locty, tis->loc[0].r_offset, tis->loc[0].w_offset);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_locty = {
+    .name = "loc",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(state, TPMLocality),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static const VMStateDescription vmstate_spapr_vtpm = {
+    .name = "spapr_vtpm",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save  = spapr_vtpm_pre_save,
+    .post_load = spapr_vtpm_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_SPAPR_VIO(vdev, SPAPRvTPMState),
+
+        VMSTATE_STRUCT_ARRAY(s.tis.loc, TPMState, TPM_TIS_NUM_LOCALITIES, 1,
+                             vmstate_locty, TPMLocality),
+
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static Property spapr_vtpm_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(SPAPRvTPMState, vdev),
+    DEFINE_PROP_STRING("tpmdev", SPAPRvTPMState, backend),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vtpm_realizefn(VIOsPAPRDevice *dev, Error **errp)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM_DEVICE(dev);
+
+    dev->crq.SendFunc = spapr_vtpm_do_crq;
+
+    s->be_driver = qemu_find_tpm(s->backend);
+    if (!s->be_driver) {
+        error_setg(errp, "spapr_vtpm: backend driver with id %s could not be "
+                   "found", s->backend);
+        return;
+    }
+
+    s->be_driver->fe_model = TPM_MODEL_SPAPR_VTPM;
+
+    if (tpm_backend_init(s->be_driver, s, &s->locty_number, &s->locty_data,
+                         spapr_vtpm_receive_cb)) {
+        error_setg(errp, "spapr_vtpm: backend driver with id %s could not be "
+                   "initialized", s->backend);
+        return;
+    }
+
+    s->s.tis.bh = qemu_bh_new(spapr_vtpm_receive_bh, s);
+}
+
+static void spapr_vtpm_initfn(Object *obj)
+{
+    SPAPRvTPMState *s = VIO_SPAPR_VTPM_DEVICE(obj);
+
+    qemu_mutex_init(&s->state_lock);
+    qemu_cond_init(&s->cmd_complete);
+}
+
+static void spapr_vtpm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->realize = spapr_vtpm_realizefn;
+    k->reset = spapr_vtpm_reset;
+    k->dt_name = "vtpm";
+    k->dt_type = "IBM,vtpm";
+    k->dt_compatible = "IBM,vtpm";
+    k->signal_mask = 0x00000001;
+    k->rtce_window_size = 0x10000000;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->props = spapr_vtpm_properties;
+    dc->vmsd = &vmstate_spapr_vtpm;
+}
+
+static const TypeInfo spapr_vtpm_info = {
+    .name          = TYPE_VIO_SPAPR_VTPM_DEVICE,
+    .parent        = TYPE_VIO_SPAPR_DEVICE,
+    .instance_size = sizeof(SPAPRvTPMState),
+    .instance_init = spapr_vtpm_initfn,
+    .class_init    = spapr_vtpm_class_init,
+};
+
+static void spapr_vtpm_register_types(void)
+{
+    type_register_static(&spapr_vtpm_info);
+    tpm_register_model(TPM_MODEL_SPAPR_VTPM);
+}
+
+type_init(spapr_vtpm_register_types)
diff --git a/hw/tpm/spapr_vtpm.h b/hw/tpm/spapr_vtpm.h
new file mode 100644
index 0000000..d4fc693
--- /dev/null
+++ b/hw/tpm/spapr_vtpm.h
@@ -0,0 +1,65 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtual TPM, aka ibmvtpm
+ *
+ * Copyright (c) 2015 IBM Corporation.
+ *
+ * Authors:
+ *    Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#ifndef TPM_SPAPR_VTPM_H
+#define TPM_SPAPR_VTPM_H
+
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+
+typedef struct vio_crq {
+    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;
+} vio_crq;
+
+typedef union spapr_vtpm_crq {
+    vio_crq s;
+    uint8_t raw[sizeof(vio_crq)];
+} spapr_vtpm_crq;
+
+#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
+
+#endif /* TPM_SPAPR_VTPM_H */
diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h
index 2299a54..5efdf4f 100644
--- a/include/hw/ppc/spapr_vio.h
+++ b/include/hw/ppc/spapr_vio.h
@@ -133,6 +133,7 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
 void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev);
 void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd);
 void spapr_vscsi_create(VIOsPAPRBus *bus);
+void spapr_vtpm_create(VIOsPAPRBus *bus);
 
 VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
 
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index c8afa17..45feee3 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -27,6 +27,7 @@ typedef enum  TPMVersion {
 } TPMVersion;
 
 TPMVersion tpm_tis_get_tpm_version(Object *obj);
+TPMVersion spapr_vtpm_get_tpm_version(Object *obj);
 
 #define TYPE_TPM_TIS                "tpm-tis"
 
diff --git a/qapi-schema.json b/qapi-schema.json
index e0ef212..2ab4dad 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3315,8 +3315,12 @@
 # @tpm-tis: TPM TIS model
 #
 # Since: 1.5
+#
+# @spapr-vtpm: PPC64 vTPM device model
+#
+# Since: 2.6
 ##
-{ 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] }
+{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'spapr-vtpm' ] }
 
 ##
 # @query-tpm-models:
-- 
2.4.3

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

end of thread, other threads:[~2016-01-04 16:14 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-04 16:14 [Qemu-devel] [PATCH v2 0/3] Add TPM support to ppc64 Stefan Berger
2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 1/3] Enable PPC64 with TPM support Stefan Berger
2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 2/3] tpm: remove TPMState usage from backend Stefan Berger
2016-01-04 16:14 ` [Qemu-devel] [PATCH v2 3/3] tpm: Support TPM for ppc64 using CRQ based interface 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).