[V2,3/9] Add persistent state handling to TPM TIS frontend driver

Submitted by Stefan Berger on March 30, 2011, 7:42 p.m.

Details

Message ID 20110330194236.643867620@linux.vnet.ibm.com
State New
Headers show

Commit Message

Stefan Berger March 30, 2011, 7:42 p.m.
This patch adds support for handling of persisten state to the TPM TIS
frontend.

The currently used buffer is determined (can only be in currently active
locality and either be a read or a write buffer) and only that buffer's content
is stored. The reverse is done when the state is restored from disk
where the buffer's content are copied into the currently used buffer.

I adapated the structure to those used by the Xen driver in order to
provide compatibility to existing state. For that I am adding Andreas
Niederl as an author to the file.

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

---
 hw/tpm_tis.c |  156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

Patch hide | download patch | download mbox

Index: qemu-git/hw/tpm_tis.c
===================================================================
--- qemu-git.orig/hw/tpm_tis.c
+++ qemu-git/hw/tpm_tis.c
@@ -6,6 +6,8 @@ 
  * Author: Stefan Berger <stefanb@us.ibm.com>
  *         David Safford <safford@us.ibm.com>
  *
+ * Xen 4 support: Andrease Niederl <andreas.niederl@iaik,tugraz.at>
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, version 2 of the
@@ -824,3 +826,157 @@  static int tpm_tis_init(ISADevice *dev)
     exit(1);
 }
 
+/* persistent state handling */
+
+static void tpm_tis_pre_save(void *opaque)
+{
+    TPMState *s = opaque;
+    uint8_t locty = s->active_locty;
+
+    qemu_mutex_lock(&s->state_lock);
+
+    /* wait for outstanding requests to complete */
+    if (IS_VALID_LOCTY(locty) && s->loc[locty].state == STATE_EXECUTION) {
+        qemu_cond_wait(&s->from_tpm_cond, &s->state_lock);
+    }
+
+#ifdef DEBUG_TIS_SR
+    fprintf(stderr,"tpm_tis: suspend: locty 0 : r_offset = %d, w_offset = %d\n",
+        s->loc[0].r_offset,
+        s->loc[0].w_offset);
+    if (s->loc[0].r_offset) {
+        tis_dump_state(opaque, 0);
+    }
+#endif
+
+    qemu_mutex_unlock(&s->state_lock);
+
+    /* copy current active read or write buffer into the buffer
+       written to disk */
+    if (IS_VALID_LOCTY(locty)) {
+        switch (s->loc[locty].state) {
+        case STATE_RECEPTION:
+            memcpy(s->buf,
+                   s->loc[locty].w_buffer.buffer,
+                   MIN(sizeof(s->buf),
+                       s->loc[locty].w_buffer.size));
+            s->offset = s->loc[locty].w_offset;
+        break;
+        case STATE_COMPLETION:
+            memcpy(s->buf,
+                   s->loc[locty].r_buffer.buffer,
+                   MIN(sizeof(s->buf),
+                       s->loc[locty].r_buffer.size));
+            s->offset = s->loc[locty].r_offset;
+        break;
+        default:
+            /* leak nothing */
+            memset(s->buf, 0x0, sizeof(s->buf));
+        break;
+        }
+    }
+
+    tis_get_active_backend()->save_volatile_data();
+}
+
+
+static int tpm_tis_post_load(void *opaque,
+                             int version_id __attribute__((unused)))
+{
+    TPMState *s = opaque;
+
+    uint8_t locty = s->active_locty;
+
+    if (IS_VALID_LOCTY(locty)) {
+        switch (s->loc[locty].state) {
+        case STATE_RECEPTION:
+            memcpy(s->loc[locty].w_buffer.buffer,
+                   s->buf,
+                   MIN(sizeof(s->buf),
+                       s->loc[locty].w_buffer.size));
+            s->loc[locty].w_offset = s->offset;
+        break;
+        case STATE_COMPLETION:
+            memcpy(s->loc[locty].r_buffer.buffer,
+                   s->buf,
+                   MIN(sizeof(s->buf),
+                       s->loc[locty].r_buffer.size));
+            s->loc[locty].r_offset = s->offset;
+        break;
+        default:
+        break;
+        }
+    }
+
+#ifdef DEBUG_TIS_SR
+    fprintf(stderr,"tpm_tis: resume : locty 0 : r_offset = %d, w_offset = %d\n",
+            s->loc[0].r_offset,
+            s->loc[0].w_offset);
+#endif
+
+    return tis_get_active_backend()->load_volatile_data(s);
+}
+
+
+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_UINT32(inte    , TPMLocality),
+        VMSTATE_UINT32(ints    , TPMLocality),
+        VMSTATE_UINT8 (access  , TPMLocality),
+        VMSTATE_UINT8 (sts     , TPMLocality),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+
+static const VMStateDescription vmstate_tpm_tis = {
+    .name = "tpm",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save  = tpm_tis_pre_save,
+    .post_load = tpm_tis_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(irq_num       , TPMState),
+        VMSTATE_UINT32(offset        , TPMState),
+        VMSTATE_BUFFER(buf           , TPMState),
+        VMSTATE_UINT8 (  active_locty, TPMState),
+        VMSTATE_UINT8 (aborting_locty, TPMState),
+        VMSTATE_UINT8 (    next_locty, TPMState),
+
+        VMSTATE_STRUCT_ARRAY(loc, TPMState, NUM_LOCALITIES, 1,
+                             vmstate_locty, TPMLocality),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static ISADeviceInfo tpm_tis_device_info = {
+    .init         = tpm_tis_init,
+    .qdev.name    = "tpm-tis",
+    .qdev.size    = sizeof(TPMState),
+    .qdev.no_user = 1,
+    .qdev.vmsd    = &vmstate_tpm_tis,
+    .qdev.reset   = tpm_tis_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("active_locality", TPMState,
+                          active_locty, NO_LOCALITY),
+        DEFINE_PROP_UINT32("irq", TPMState,
+                           irq_num, TPM_TIS_IRQ),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+
+static void tpm_tis_register_device(void)
+{
+    isa_qdev_register(&tpm_tis_device_info);
+}
+
+device_init(tpm_tis_register_device)