Patchwork [V4,03/10] Add persistent state handling to TPM TIS frontend driver

login
register
mail settings
Submitter Stefan Berger
Date May 6, 2011, 5:32 p.m.
Message ID <20110506173245.282675435@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/94413/
State New
Headers show

Comments

Stefan Berger - May 6, 2011, 5:32 p.m.
This patch adds support for handling of persistent 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.

To keep compatibility with existing Xen the VMStateDescription was adapted
to be compatible with existing state. For that I am adding Andreas
Niederl as an author to the file.

v4:
 - main thread releases the 'state' lock while periodically calling the
   backends function that may request it to write data into block storage.

v3:
 - all functions prefixed with tis_
 - while the main thread is waiting for an outstanding TPM command to finish,
   it periodically does some work (writes data to the block storage)

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

---
 hw/tpm_tis.c |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 167 insertions(+)
Markus Armbruster - May 18, 2011, 7:25 a.m.
Stefan Berger <stefanb@linux.vnet.ibm.com> writes:

> This patch adds support for handling of persistent 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.
>
> To keep compatibility with existing Xen the VMStateDescription was adapted
> to be compatible with existing state. For that I am adding Andreas
> Niederl as an author to the file.
>
> v4:
>  - main thread releases the 'state' lock while periodically calling the
>    backends function that may request it to write data into block storage.
>
> v3:
>  - all functions prefixed with tis_
>  - while the main thread is waiting for an outstanding TPM command to finish,
>    it periodically does some work (writes data to the block storage)
>
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>
> ---
>  hw/tpm_tis.c |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 167 insertions(+)
>
> Index: qemu-git/hw/tpm_tis.c
> ===================================================================
> --- qemu-git.orig/hw/tpm_tis.c
> +++ qemu-git/hw/tpm_tis.c
[...]
> +static ISADeviceInfo tis_device_info = {
> +    .init         = tis_init,
> +    .qdev.name    = "tpm-tis",
> +    .qdev.size    = sizeof(TPMState),
> +    .qdev.no_user = 1,
> +    .qdev.vmsd    = &vmstate_tis,
> +    .qdev.reset   = 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 tis_register_device(void)
> +{
> +    isa_qdev_register(&tis_device_info);
> +}
> +
> +device_init(tis_register_device)

Why is this device no_user?
Stefan Berger - May 18, 2011, 10:51 a.m.
On 05/18/2011 03:25 AM, Markus Armbruster wrote:
> Stefan Berger<stefanb@linux.vnet.ibm.com>  writes:
>
> Why is this device no_user?
Because I instantiated it still with isa_create_simple(). This is going 
to change in v5.

Thanks.
    Stefan
Stefan Berger - May 25, 2011, 2:49 p.m.
On 05/18/2011 03:25 AM, Markus Armbruster wrote:
> Stefan Berger<stefanb@linux.vnet.ibm.com>  writes:
>
>> +static void tis_register_device(void)
>> +{
>> +    isa_qdev_register(&tis_device_info);
>> +}
>> +
>> +device_init(tis_register_device)
> Why is this device no_user?
In case you want to review V5, I posted it:

http://lists.nongnu.org/archive/html/qemu-devel/2011-05/msg02091.html

Regards,
    Stefan

Patch

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
@@ -869,3 +871,168 @@  static int tis_init(ISADevice *dev)
     return -1;
 }
 
+/* persistent state handling */
+
+static void 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) {
+        if (!active_be->job_for_main_thread) {
+            qemu_cond_wait(&s->from_tpm_cond, &s->state_lock);
+        } else {
+            while (s->loc[locty].state == STATE_EXECUTION) {
+                qemu_mutex_unlock(&s->state_lock);
+
+                active_be->job_for_main_thread(NULL);
+                usleep(10000);
+
+                qemu_mutex_lock(&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 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_tis = {
+    .name = "tpm",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save  = tis_pre_save,
+    .post_load = 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 tis_device_info = {
+    .init         = tis_init,
+    .qdev.name    = "tpm-tis",
+    .qdev.size    = sizeof(TPMState),
+    .qdev.no_user = 1,
+    .qdev.vmsd    = &vmstate_tis,
+    .qdev.reset   = 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 tis_register_device(void)
+{
+    isa_qdev_register(&tis_device_info);
+}
+
+device_init(tis_register_device)