[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] drivers/tpm-xen: Change vTPM shared page ABI



This changes the vTPM shared page ABI from a copy of the Xen network
interface to a single-page interface that better reflects the expected
behavior of a TPM: only a single request packet can be sent at any given
time, and every packet sent generates a single response packet.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
---
 drivers/char/tpm/xen-tpmfront_if.c | 219 ++++++++++---------------------------
 include/xen/interface/io/tpmif.h   |  45 +++-----
 2 files changed, 73 insertions(+), 191 deletions(-)

diff --git a/drivers/char/tpm/xen-tpmfront_if.c 
b/drivers/char/tpm/xen-tpmfront_if.c
index 649aee6..b1f95c0 100644
--- a/drivers/char/tpm/xen-tpmfront_if.c
+++ b/drivers/char/tpm/xen-tpmfront_if.c
@@ -53,7 +53,7 @@
 struct tpm_private {
        struct tpm_chip *chip;
 
-       struct tpmif_tx_interface *tx;
+       struct vtpm_shared_page *page;
        atomic_t refcnt;
        unsigned int evtchn;
        u8 is_connected;
@@ -61,8 +61,6 @@ struct tpm_private {
 
        spinlock_t tx_lock;
 
-       struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE];
-
        atomic_t tx_busy;
        void *tx_remember;
 
@@ -73,15 +71,7 @@ struct tpm_private {
        int ring_ref;
 };
 
-struct tx_buffer {
-       unsigned int size;      /* available space in data */
-       unsigned int len;       /* used space in data */
-       unsigned char *data;    /* pointer to a page */
-};
-
-
 /* locally visible variables */
-static grant_ref_t gref_head;
 static struct tpm_private *my_priv;
 
 /* local function prototypes */
@@ -92,8 +82,6 @@ static int tpmif_connect(struct xenbus_device *dev,
                struct tpm_private *tp,
                domid_t domid);
 static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
-static int tpmif_allocate_tx_buffers(struct tpm_private *tp);
-static void tpmif_free_tx_buffers(struct tpm_private *tp);
 static void tpmif_set_connected_state(struct tpm_private *tp,
                u8 newstate);
 static int tpm_xmit(struct tpm_private *tp,
@@ -101,52 +89,6 @@ static int tpm_xmit(struct tpm_private *tp,
                void *remember);
 static void destroy_tpmring(struct tpm_private *tp);
 
-static inline int
-tx_buffer_copy(struct tx_buffer *txb, const u8 *src, int len,
-               int isuserbuffer)
-{
-       int copied = len;
-
-       if (len > txb->size)
-               copied = txb->size;
-       if (isuserbuffer) {
-               if (copy_from_user(txb->data, src, copied))
-                       return -EFAULT;
-       } else {
-               memcpy(txb->data, src, copied);
-       }
-       txb->len = len;
-       return copied;
-}
-
-static inline struct tx_buffer *tx_buffer_alloc(void)
-{
-       struct tx_buffer *txb;
-
-       txb = kzalloc(sizeof(struct tx_buffer), GFP_KERNEL);
-       if (!txb)
-               return NULL;
-
-       txb->len = 0;
-       txb->size = PAGE_SIZE;
-       txb->data = (unsigned char *)__get_free_page(GFP_KERNEL);
-       if (txb->data == NULL) {
-               kfree(txb);
-               txb = NULL;
-       }
-
-       return txb;
-}
-
-
-static inline void tx_buffer_free(struct tx_buffer *txb)
-{
-       if (txb) {
-               free_page((long)txb->data);
-               kfree(txb);
-       }
-}
-
 /**************************************************************
   Utility function for the tpm_private structure
  **************************************************************/
@@ -162,15 +104,12 @@ static void tpm_private_put(void)
        if (!atomic_dec_and_test(&my_priv->refcnt))
                return;
 
-       tpmif_free_tx_buffers(my_priv);
        kfree(my_priv);
        my_priv = NULL;
 }
 
 static struct tpm_private *tpm_private_get(void)
 {
-       int err;
-
        if (my_priv) {
                atomic_inc(&my_priv->refcnt);
                return my_priv;
@@ -181,9 +120,6 @@ static struct tpm_private *tpm_private_get(void)
                return NULL;
 
        tpm_private_init(my_priv);
-       err = tpmif_allocate_tx_buffers(my_priv);
-       if (err < 0)
-               tpm_private_put();
 
        return my_priv;
 }
@@ -218,22 +154,22 @@ int vtpm_vd_send(struct tpm_private *tp,
 static int setup_tpmring(struct xenbus_device *dev,
                struct tpm_private *tp)
 {
-       struct tpmif_tx_interface *sring;
+       struct vtpm_shared_page *sring;
        int err;
 
        tp->ring_ref = GRANT_INVALID_REF;
 
-       sring = (void *)__get_free_page(GFP_KERNEL);
+       sring = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
        if (!sring) {
                xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
                return -ENOMEM;
        }
-       tp->tx = sring;
+       tp->page = sring;
 
-       err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx));
+       err = xenbus_grant_ring(dev, virt_to_mfn(tp->page));
        if (err < 0) {
                free_page((unsigned long)sring);
-               tp->tx = NULL;
+               tp->page = NULL;
                xenbus_dev_fatal(dev, err, "allocating grant reference");
                goto fail;
        }
@@ -256,9 +192,9 @@ static void destroy_tpmring(struct tpm_private *tp)
 
        if (tp->ring_ref != GRANT_INVALID_REF) {
                gnttab_end_foreign_access(tp->ring_ref,
-                               0, (unsigned long)tp->tx);
+                               0, (unsigned long)tp->page);
                tp->ring_ref = GRANT_INVALID_REF;
-               tp->tx = NULL;
+               tp->page = NULL;
        }
 
        if (tp->evtchn)
@@ -302,6 +238,13 @@ again:
                goto abort_transaction;
        }
 
+       err = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1");
+       if (err) {
+               message = "writing feature-protocol-v2";
+               goto abort_transaction;
+       }
+
+
        err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
                goto again;
@@ -331,6 +274,7 @@ static void backend_changed(struct xenbus_device *dev,
                enum xenbus_state backend_state)
 {
        struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
+       int val;
 
        switch (backend_state) {
        case XenbusStateInitialising:
@@ -342,7 +286,14 @@ static void backend_changed(struct xenbus_device *dev,
                break;
 
        case XenbusStateConnected:
-               tpmif_set_connected_state(tp, 1);
+               if (xenbus_scanf(XBT_NIL, dev->otherend,
+                               "feature-protocol-v2", "%d", &val) < 0)
+                       val = 0;
+               if (val)
+                       tpmif_set_connected_state(tp, 1);
+               else
+                       xenbus_dev_fatal(dev, -EINVAL,
+                                        "vTPM protocol 2 required");
                break;
 
        case XenbusStateClosing:
@@ -470,62 +421,41 @@ static DEFINE_XENBUS_DRIVER(tpmfront, ,
                .suspend = tpmfront_suspend,
                );
 
-static int tpmif_allocate_tx_buffers(struct tpm_private *tp)
-{
-       unsigned int i;
-
-       for (i = 0; i < TPMIF_TX_RING_SIZE; i++) {
-               tp->tx_buffers[i] = tx_buffer_alloc();
-               if (!tp->tx_buffers[i]) {
-                       tpmif_free_tx_buffers(tp);
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-static void tpmif_free_tx_buffers(struct tpm_private *tp)
-{
-       unsigned int i;
-
-       for (i = 0; i < TPMIF_TX_RING_SIZE; i++)
-               tx_buffer_free(tp->tx_buffers[i]);
-}
-
 static void tpmif_rx_action(unsigned long priv)
 {
        struct tpm_private *tp = (struct tpm_private *)priv;
-       int i = 0;
        unsigned int received;
        unsigned int offset = 0;
        u8 *buffer;
-       struct tpmif_tx_request *tx = &tp->tx->ring[i].req;
+       struct vtpm_shared_page *shr = tp->page;
+       int state = shr->state;
+
+       switch (state) {
+       case VTPM_STATE_IDLE:
+               received = 0;
+               break;
+       case VTPM_STATE_FINISH:
+               received = shr->length;
+               break;
+       default:
+               return;
+       }
 
        atomic_set(&tp->tx_busy, 0);
        wake_up_interruptible(&tp->wait_q);
 
-       received = tx->size;
+       offset = sizeof(*shr) + 4*shr->nr_extra_pages;
+
+       if (offset > PAGE_SIZE || offset + received > PAGE_SIZE) {
+               printk(KERN_WARNING "tpmif_rx_action packet too large\n");
+               return;
+       }
 
        buffer = kmalloc(received, GFP_ATOMIC);
        if (!buffer)
                return;
 
-       for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) {
-               struct tx_buffer *txb = tp->tx_buffers[i];
-               struct tpmif_tx_request *tx;
-               unsigned int tocopy;
-
-               tx = &tp->tx->ring[i].req;
-               tocopy = tx->size;
-               if (tocopy > PAGE_SIZE)
-                       tocopy = PAGE_SIZE;
-
-               memcpy(&buffer[offset], txb->data, tocopy);
-
-               gnttab_release_grant_reference(&gref_head, tx->ref);
-
-               offset += tocopy;
-       }
+       memcpy(buffer, offset + (u8*)shr, received);
 
        vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember);
        kfree(buffer);
@@ -550,8 +480,7 @@ static int tpm_xmit(struct tpm_private *tp,
                const u8 *buf, size_t count, int isuserbuffer,
                void *remember)
 {
-       struct tpmif_tx_request *tx;
-       int i;
+       struct vtpm_shared_page *shr;
        unsigned int offset = 0;
 
        spin_lock_irq(&tp->tx_lock);
@@ -566,48 +495,23 @@ static int tpm_xmit(struct tpm_private *tp,
                return -EIO;
        }
 
-       for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) {
-               struct tx_buffer *txb = tp->tx_buffers[i];
-               int copied;
-
-               if (!txb) {
-                       spin_unlock_irq(&tp->tx_lock);
-                       return -EFAULT;
-               }
-
-               copied = tx_buffer_copy(txb, &buf[offset], count,
-                               isuserbuffer);
-               if (copied < 0) {
-                       /* An error occurred */
-                       spin_unlock_irq(&tp->tx_lock);
-                       return copied;
-               }
-               count -= copied;
-               offset += copied;
-
-               tx = &tp->tx->ring[i].req;
-               tx->addr = virt_to_machine(txb->data).maddr;
-               tx->size = txb->len;
-               tx->unused = 0;
-
-               /* Get the granttable reference for this page. */
-               tx->ref = gnttab_claim_grant_reference(&gref_head);
-               if (tx->ref == -ENOSPC) {
-                       spin_unlock_irq(&tp->tx_lock);
-                       return -ENOSPC;
-               }
-               gnttab_grant_foreign_access_ref(tx->ref,
-                               tp->backend_id,
-                               virt_to_mfn(txb->data),
-                               0 /*RW*/);
-               wmb();
-       }
+       shr = tp->page;
+       offset = sizeof(*shr) + 4*shr->nr_extra_pages;
+
+       if (offset > PAGE_SIZE)
+               return -EIO;
+
+       if (offset + count > PAGE_SIZE)
+               count = PAGE_SIZE - offset;
+
+       memcpy(offset + (u8*)shr, buf, count);
+       shr->length = count;
+       barrier();
+       shr->state = VTPM_STATE_SUBMIT;
 
        atomic_set(&tp->tx_busy, 1);
        tp->tx_remember = remember;
 
-       mb();
-
        notify_remote_via_evtchn(tp->evtchn);
 
        spin_unlock_irq(&tp->tx_lock);
@@ -667,12 +571,6 @@ static int __init tpmif_init(void)
        if (!tp)
                return -ENOMEM;
 
-       if (gnttab_alloc_grant_references(TPMIF_TX_RING_SIZE,
-                               &gref_head) < 0) {
-               tpm_private_put();
-               return -EFAULT;
-       }
-
        return xenbus_register_frontend(&tpmfront_driver);
 }
 module_init(tpmif_init);
@@ -680,7 +578,6 @@ module_init(tpmif_init);
 static void __exit tpmif_exit(void)
 {
        xenbus_unregister_driver(&tpmfront_driver);
-       gnttab_free_grant_references(gref_head);
        tpm_private_put();
 }
 module_exit(tpmif_exit);
diff --git a/include/xen/interface/io/tpmif.h b/include/xen/interface/io/tpmif.h
index c9e7294..2536337 100644
--- a/include/xen/interface/io/tpmif.h
+++ b/include/xen/interface/io/tpmif.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  * tpmif.h
  *
- * TPM I/O interface for Xen guest OSes.
+ * TPM I/O interface for Xen guest OSes, v2
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -21,45 +21,30 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  *
- * Copyright (c) 2005, IBM Corporation
- *
- * Author: Stefan Berger, stefanb@xxxxxxxxxx
- * Grant table support: Mahadevan Gomathisankaran
- *
- * This code has been derived from tools/libxc/xen/io/netif.h
- *
- * Copyright (c) 2003-2004, Keir Fraser
  */
 
 #ifndef __XEN_PUBLIC_IO_TPMIF_H__
 #define __XEN_PUBLIC_IO_TPMIF_H__
 
-#include "../grant_table.h"
-
-struct tpmif_tx_request {
-       unsigned long addr;   /* Machine address of packet.   */
-       grant_ref_t ref;      /* grant table access reference */
-       uint16_t unused;
-       uint16_t size;        /* Packet size in bytes.        */
+enum vtpm_shared_page_state {
+       VTPM_STATE_IDLE,         /* no contents / vTPM idle / cancel complete */
+       VTPM_STATE_SUBMIT,       /* request ready / vTPM working */
+       VTPM_STATE_FINISH,       /* response ready / vTPM idle */
+       VTPM_STATE_CANCEL,       /* cancel requested / vTPM working */
 };
-struct tpmif_tx_request;
+/* The backend should only change state to IDLE or FINISH, while the
+ * frontend should only change to SUBMIT or CANCEL. */
 
-/*
- * The TPMIF_TX_RING_SIZE defines the number of pages the
- * front-end and backend can exchange (= size of array).
- */
-#define TPMIF_TX_RING_SIZE 1
 
-/* This structure must fit in a memory page. */
+struct vtpm_shared_page {
+       uint32_t length;         /* request/response length in bytes */
 
-struct tpmif_ring {
-       struct tpmif_tx_request req;
-};
-struct tpmif_ring;
+       uint8_t state;           /* enum vtpm_shared_page_state */
+       uint8_t locality;        /* for the current request */
+       uint8_t pad;
 
-struct tpmif_tx_interface {
-       struct tpmif_ring ring[TPMIF_TX_RING_SIZE];
+       uint8_t nr_extra_pages;  /* extra pages for long packets; may be zero */
+       uint32_t extra_pages[0]; /* grant IDs; length is actually 
nr_extra_pages */
 };
-struct tpmif_tx_interface;
 
 #endif
-- 
1.8.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.