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

[Xen-devel] [PATCH v5.2] mini-os/tpm{back, front}: Change 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. This
protocol change should also increase efficiency as it avoids mapping and
unmapping grants when possible. The vtpm xenbus device now requires a
feature-protocol-v2 node in xenstore to avoid conflicts with existing
(xen-patched) kernels supporting the old interface.

While the contents of the shared page have been defined to allow packets
larger than a single page (actually 4088 bytes) by allowing the client
to add extra grant references, the mapping of these extra references has
not been implemented; a feature node in xenstore may be used in the
future to indicate full support for the multi-page protocol. Most uses
of the TPM should not require this feature.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
Cc: Jan Beulich <JBeulich@xxxxxxxx>

---

Changes from v5.1: add memory barriers and document the protocol

Changes from v5: fix XenbusStateInitialised handling

Changes from v4: use feature-protocol-v2 nodes instead of changing the
device name; add command cancellation support to the protocol.

 extras/mini-os/include/tpmback.h  |   1 +
 extras/mini-os/include/tpmfront.h |   7 +-
 extras/mini-os/tpmback.c          | 166 +++++++++++++++++++-------------------
 extras/mini-os/tpmfront.c         | 144 ++++++++++++++++++---------------
 xen/include/public/io/tpmif.h     |  66 +++++++++++++++
 5 files changed, 232 insertions(+), 152 deletions(-)

diff --git a/extras/mini-os/include/tpmback.h b/extras/mini-os/include/tpmback.h
index ff86732..ec9eda4 100644
--- a/extras/mini-os/include/tpmback.h
+++ b/extras/mini-os/include/tpmback.h
@@ -43,6 +43,7 @@
 
 struct tpmcmd {
    domid_t domid;              /* Domid of the frontend */
+   uint8_t locality;    /* Locality requested by the frontend */
    unsigned int handle;        /* Handle of the frontend */
    unsigned char uuid[16];                     /* uuid of the tpm interface */
 
diff --git a/extras/mini-os/include/tpmfront.h 
b/extras/mini-os/include/tpmfront.h
index fd2cb17..a0c7c4d 100644
--- a/extras/mini-os/include/tpmfront.h
+++ b/extras/mini-os/include/tpmfront.h
@@ -37,9 +37,7 @@ struct tpmfront_dev {
    grant_ref_t ring_ref;
    evtchn_port_t evtchn;
 
-   tpmif_tx_interface_t* tx;
-
-   void** pages;
+   vtpm_shared_page_t *page;
 
    domid_t bedomid;
    char* nodename;
@@ -77,6 +75,9 @@ void shutdown_tpmfront(struct tpmfront_dev* dev);
  * */
 int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, 
uint8_t** resp, size_t* resplen);
 
+/* Set the locality used for communicating with a vTPM */
+int tpmfront_set_locality(struct tpmfront_dev* dev, int locality);
+
 #ifdef HAVE_LIBC
 #include <sys/stat.h>
 /* POSIX IO functions:
diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c
index 658fed1..d68ad2b 100644
--- a/extras/mini-os/tpmback.c
+++ b/extras/mini-os/tpmback.c
@@ -86,10 +86,7 @@ struct tpmif {
    evtchn_port_t evtchn;
 
    /* Shared page */
-   tpmif_tx_interface_t* tx;
-
-   /* pointer to TPMIF_RX_RING_SIZE pages */
-   void** pages;
+   vtpm_shared_page_t *page;
 
    enum xenbus_state state;
    enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
@@ -266,6 +263,7 @@ int insert_tpmif(tpmif_t* tpmif)
    unsigned int i, j;
    tpmif_t* tmp;
    char* err;
+   char path[512];
 
    local_irq_save(flags);
 
@@ -303,6 +301,16 @@ int insert_tpmif(tpmif_t* tpmif)
 
    local_irq_restore(flags);
 
+   snprintf(path, 512, "backend/vtpm/%u/%u/feature-protocol-v2", (unsigned 
int) tpmif->domid, tpmif->handle);
+   if ((err = xenbus_write(XBT_NIL, path, "1")))
+   {
+      /* if we got an error here we should carefully remove the interface and 
then return */
+      TPMBACK_ERR("Unable to write feature-protocol-v2 node: %s\n", err);
+      free(err);
+      remove_tpmif(tpmif);
+      goto error_post_irq;
+   }
+
    /*Listen for state changes on the new interface */
    if((err = xenbus_watch_path_token(XBT_NIL, tpmif->fe_state_path, 
tpmif->fe_state_path, &gtpmdev.events)))
    {
@@ -312,7 +320,6 @@ int insert_tpmif(tpmif_t* tpmif)
       remove_tpmif(tpmif);
       goto error_post_irq;
    }
-
    return 0;
 error:
    local_irq_restore(flags);
@@ -386,8 +393,7 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int 
handle)
    tpmif->fe_state_path = NULL;
    tpmif->state = XenbusStateInitialising;
    tpmif->status = DISCONNECTED;
-   tpmif->tx = NULL;
-   tpmif->pages = NULL;
+   tpmif->page = NULL;
    tpmif->flags = 0;
    memset(tpmif->uuid, 0, sizeof(tpmif->uuid));
    return tpmif;
@@ -395,9 +401,6 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int 
handle)
 
 void __free_tpmif(tpmif_t* tpmif)
 {
-   if(tpmif->pages) {
-      free(tpmif->pages);
-   }
    if(tpmif->fe_path) {
       free(tpmif->fe_path);
    }
@@ -430,12 +433,6 @@ tpmif_t* new_tpmif(domid_t domid, unsigned int handle)
       goto error;
    }
 
-   /* allocate pages to be used for shared mapping */
-   if((tpmif->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE)) == NULL) {
-      goto error;
-   }
-   memset(tpmif->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE);
-
    if(tpmif_change_state(tpmif, XenbusStateInitWait)) {
       goto error;
    }
@@ -486,7 +483,7 @@ void free_tpmif(tpmif_t* tpmif)
       tpmif->status = DISCONNECTING;
       mask_evtchn(tpmif->evtchn);
 
-      if(gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1)) {
+      if(gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->page, 1)) {
         TPMBACK_ERR("%u/%u Error occured while trying to unmap shared page\n", 
(unsigned int) tpmif->domid, tpmif->handle);
       }
 
@@ -529,15 +526,28 @@ void free_tpmif(tpmif_t* tpmif)
 void tpmback_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
 {
    tpmif_t* tpmif = (tpmif_t*) data;
-   tpmif_tx_request_t* tx = &tpmif->tx->ring[0].req;
-   /* Throw away 0 size events, these can trigger from event channel unmasking 
*/
-   if(tx->size == 0)
-      return;
-
-   TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) tpmif->domid, 
tpmif->handle);
-   tpmif_req_ready(tpmif);
-   wake_up(&waitq);
+   vtpm_shared_page_t* pg = tpmif->page;
 
+   switch (pg->state)
+   {
+   case VTPM_STATE_SUBMIT:
+      TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) tpmif->domid, 
tpmif->handle);
+      tpmif_req_ready(tpmif);
+      wake_up(&waitq);
+      break;
+   case VTPM_STATE_CANCEL:
+      /* If we are busy with a request, do nothing */
+      if (tpmif->flags & TPMIF_REQ_READY)
+         return;
+      /* Acknowledge the cancellation if we are idle */
+      pg->state = VTPM_STATE_IDLE;
+      wmb();
+      notify_remote_via_evtchn(tpmif->evtchn);
+      return;
+   default:
+      /* Spurious wakeup; do nothing */
+      return;
+   }
 }
 
 /* Connect to frontend */
@@ -584,12 +594,25 @@ int connect_fe(tpmif_t* tpmif)
    }
    free(value);
 
+   /* Check that protocol v2 is being used */
+   snprintf(path, 512, "%s/feature-protocol-v2", tpmif->fe_path);
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMBACK_ERR("Unable to read %s during tpmback initialization! error = 
%s\n", path, err);
+      free(err);
+      return -1;
+   }
+   if(strcmp(value, "1")) {
+      TPMBACK_ERR("%s has an invalid value (%s)\n", path, value);
+      free(value);
+      return -1;
+   }
+   free(value);
+
    domid = tpmif->domid;
-   if((tpmif->tx = gntmap_map_grant_refs(&gtpmdev.map, 1, &domid, 0, &ringref, 
PROT_READ | PROT_WRITE)) == NULL) {
+   if((tpmif->page = gntmap_map_grant_refs(&gtpmdev.map, 1, &domid, 0, 
&ringref, PROT_READ | PROT_WRITE)) == NULL) {
       TPMBACK_ERR("Failed to map grant reference %u/%u\n", (unsigned int) 
tpmif->domid, tpmif->handle);
       return -1;
    }
-   memset(tpmif->tx, 0, PAGE_SIZE);
 
    /*Bind the event channel */
    if((evtchn_bind_interdomain(tpmif->domid, evtchn, tpmback_handler, tpmif, 
&tpmif->evtchn)))
@@ -618,7 +641,7 @@ error_post_evtchn:
    mask_evtchn(tpmif->evtchn);
    unbind_evtchn(tpmif->evtchn);
 error_post_map:
-   gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1);
+   gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->page, 1);
    return -1;
 }
 
@@ -633,9 +656,9 @@ static int frontend_changed(tpmif_t* tpmif)
 
    switch (state) {
       case XenbusStateInitialising:
-      case XenbusStateInitialised:
         break;
 
+      case XenbusStateInitialised:
       case XenbusStateConnected:
         if(connect_fe(tpmif)) {
            TPMBACK_ERR("Failed to connect to front end %u/%u\n", (unsigned 
int) tpmif->domid, tpmif->handle);
@@ -874,6 +897,7 @@ void shutdown_tpmback(void)
 inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, 
unsigned char uuid[16])
 {
    tpmcmd->domid = domid;
+   tpmcmd->locality = -1;
    tpmcmd->handle = handle;
    memcpy(tpmcmd->uuid, uuid, sizeof(tpmcmd->uuid));
    tpmcmd->req = NULL;
@@ -884,12 +908,12 @@ inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, 
unsigned int handle, un
 
 tpmcmd_t* get_request(tpmif_t* tpmif) {
    tpmcmd_t* cmd;
-   tpmif_tx_request_t* tx;
-   int offset;
-   int tocopy;
-   int i;
-   uint32_t domid;
+   vtpm_shared_page_t* shr;
+   unsigned int offset;
    int flags;
+#ifdef TPMBACK_PRINT_DEBUG
+   int i;
+#endif
 
    local_irq_save(flags);
 
@@ -899,35 +923,22 @@ tpmcmd_t* get_request(tpmif_t* tpmif) {
    }
    init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid);
 
-   tx = &tpmif->tx->ring[0].req;
-   cmd->req_len = tx->size;
+   shr = tpmif->page;
+   cmd->req_len = shr->length;
+   cmd->locality = shr->locality;
+   offset = sizeof(*shr) + 4*shr->nr_extra_pages;
+   if (offset > PAGE_SIZE || offset + cmd->req_len > PAGE_SIZE) {
+      TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned 
int) tpmif->domid, tpmif->handle);
+      goto error;
+   }
    /* Allocate the buffer */
    if(cmd->req_len) {
       if((cmd->req = malloc(cmd->req_len)) == NULL) {
         goto error;
       }
    }
-   /* Copy the bits from the shared pages */
-   offset = 0;
-   for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->req_len; ++i) {
-      tx = &tpmif->tx->ring[i].req;
-
-      /* Map the page with the data */
-      domid = (uint32_t)tpmif->domid;
-      if((tpmif->pages[i] = gntmap_map_grant_refs(&gtpmdev.map, 1, &domid, 0, 
&tx->ref, PROT_READ)) == NULL) {
-        TPMBACK_ERR("%u/%u Unable to map shared page during read!\n", 
(unsigned int) tpmif->domid, tpmif->handle);
-        goto error;
-      }
-
-      /* do the copy now */
-      tocopy = min(cmd->req_len - offset, PAGE_SIZE);
-      memcpy(&cmd->req[offset], tpmif->pages[i], tocopy);
-      offset += tocopy;
-
-      /* release the page */
-      gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->pages[i], 1);
-
-   }
+   /* Copy the bits from the shared page(s) */
+   memcpy(cmd->req, offset + (uint8_t*)shr, cmd->req_len);
 
 #ifdef TPMBACK_PRINT_DEBUG
    TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u", (unsigned int) 
tpmif->domid, tpmif->handle, cmd->req_len);
@@ -958,38 +969,24 @@ error:
 
 void send_response(tpmcmd_t* cmd, tpmif_t* tpmif)
 {
-   tpmif_tx_request_t* tx;
-   int offset;
-   int i;
-   uint32_t domid;
-   int tocopy;
+   vtpm_shared_page_t* shr;
+   unsigned int offset;
    int flags;
+#ifdef TPMBACK_PRINT_DEBUG
+int i;
+#endif
 
    local_irq_save(flags);
 
-   tx = &tpmif->tx->ring[0].req;
-   tx->size = cmd->resp_len;
-
-   offset = 0;
-   for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->resp_len; ++i) {
-      tx = &tpmif->tx->ring[i].req;
-
-      /* Map the page with the data */
-      domid = (uint32_t)tpmif->domid;
-      if((tpmif->pages[i] = gntmap_map_grant_refs(&gtpmdev.map, 1, &domid, 0, 
&tx->ref, PROT_WRITE)) == NULL) {
-        TPMBACK_ERR("%u/%u Unable to map shared page during write!\n", 
(unsigned int) tpmif->domid, tpmif->handle);
-        goto error;
-      }
-
-      /* do the copy now */
-      tocopy = min(cmd->resp_len - offset, PAGE_SIZE);
-      memcpy(tpmif->pages[i], &cmd->resp[offset], tocopy);
-      offset += tocopy;
-
-      /* release the page */
-      gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->pages[i], 1);
+   shr = tpmif->page;
+   shr->length = cmd->resp_len;
 
+   offset = sizeof(*shr) + 4*shr->nr_extra_pages;
+   if (offset > PAGE_SIZE || offset + cmd->resp_len > PAGE_SIZE) {
+      TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned 
int) tpmif->domid, tpmif->handle);
+      goto error;
    }
+   memcpy(offset + (uint8_t*)shr, cmd->resp, cmd->resp_len);
 
 #ifdef TPMBACK_PRINT_DEBUG
    TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int) 
tpmif->domid, tpmif->handle, cmd->resp_len);
@@ -1003,6 +1000,9 @@ void send_response(tpmcmd_t* cmd, tpmif_t* tpmif)
 #endif
    /* clear the ready flag and send the event channel notice to the frontend */
    tpmif_req_finished(tpmif);
+   barrier();
+   shr->state = VTPM_STATE_FINISH;
+   wmb();
    notify_remote_via_evtchn(tpmif->evtchn);
 error:
    local_irq_restore(flags);
diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c
index 0218d7f..9f930b5 100644
--- a/extras/mini-os/tpmfront.c
+++ b/extras/mini-os/tpmfront.c
@@ -47,11 +47,21 @@
 
 void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data) {
    struct tpmfront_dev* dev = (struct tpmfront_dev*) data;
+   vtpm_shared_page_t* shr = dev->page;
    /*If we get a response when we didnt make a request, just ignore it */
    if(!dev->waiting) {
       return;
    }
 
+   switch (shr->state) {
+   case VTPM_STATE_FINISH: /* request was completed */
+   case VTPM_STATE_IDLE:   /* request was cancelled */
+      break;
+   default:
+      /* Spurious wakeup; do nothing, request is still pending */
+      return;
+   }
+
    dev->waiting = 0;
 #ifdef HAVE_LIBC
    if(dev->fd >= 0) {
@@ -176,7 +186,7 @@ static int wait_for_backend_state_changed(struct 
tpmfront_dev* dev, XenbusState
         ret = wait_for_backend_closed(&events, path);
         break;
       default:
-        break;
+         TPMFRONT_ERR("Bad wait state %d, ignoring\n", state);
    }
 
    if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) {
@@ -190,13 +200,13 @@ static int tpmfront_connect(struct tpmfront_dev* dev)
 {
    char* err;
    /* Create shared page */
-   dev->tx = (tpmif_tx_interface_t*) alloc_page();
-   if(dev->tx == NULL) {
+   dev->page = (vtpm_shared_page_t*) alloc_page();
+   if(dev->page == NULL) {
       TPMFRONT_ERR("Unable to allocate page for shared memory\n");
       goto error;
    }
-   memset(dev->tx, 0, PAGE_SIZE);
-   dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->tx), 0);
+   memset(dev->page, 0, PAGE_SIZE);
+   dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->page), 
0);
    TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref);
 
    /*Create event channel */
@@ -228,7 +238,7 @@ error_postevtchn:
       unbind_evtchn(dev->evtchn);
 error_postmap:
       gnttab_end_access(dev->ring_ref);
-      free_page(dev->tx);
+      free_page(dev->page);
 error:
    return -1;
 }
@@ -240,7 +250,6 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename)
    char path[512];
    char* value, *err;
    unsigned long long ival;
-   int i;
 
    printk("============= Init TPM Front ================\n");
 
@@ -279,6 +288,15 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename)
       goto error;
    }
 
+   /* Publish protocol v2 feature */
+   snprintf(path, 512, "%s/feature-protocol-v2", dev->nodename);
+   if ((err = xenbus_write(XBT_NIL, path, "1")))
+   {
+      TPMFRONT_ERR("Unable to write feature-protocol-v2 node: %s\n", err);
+      free(err);
+      goto error;
+   }
+
    /* Create and publish grant reference and event channel */
    if (tpmfront_connect(dev)) {
       goto error;
@@ -289,18 +307,19 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename)
       goto error;
    }
 
-   /* Allocate pages that will contain the messages */
-   dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE);
-   if(dev->pages == NULL) {
+   /* Ensure backend is also using protocol v2 */
+   snprintf(path, 512, "%s/feature-protocol-v2", dev->bepath);
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMFRONT_ERR("Unable to read %s during tpmfront initialization! error = 
%s\n", path, err);
+      free(err);
       goto error;
    }
-   memset(dev->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE);
-   for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) {
-      dev->pages[i] = (void*)alloc_page();
-      if(dev->pages[i] == NULL) {
-        goto error;
-      }
+   if(strcmp(value, "1")) {
+      TPMFRONT_ERR("%s has an invalid value (%s)\n", path, value);
+      free(value);
+      goto error;
    }
+   free(value);
 
    TPMFRONT_LOG("Initialization Completed successfully\n");
 
@@ -314,8 +333,6 @@ void shutdown_tpmfront(struct tpmfront_dev* dev)
 {
    char* err;
    char path[512];
-   int i;
-   tpmif_tx_request_t* tx;
    if(dev == NULL) {
       return;
    }
@@ -349,27 +366,12 @@ void shutdown_tpmfront(struct tpmfront_dev* dev)
       /* Wait for the backend to close and unmap shared pages, ignore any 
errors */
       wait_for_backend_state_changed(dev, XenbusStateClosed);
 
-      /* Cleanup any shared pages */
-      if(dev->pages) {
-        for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) {
-           if(dev->pages[i]) {
-              tx = &dev->tx->ring[i].req;
-              if(tx->ref != 0) {
-                 gnttab_end_access(tx->ref);
-              }
-              free_page(dev->pages[i]);
-           }
-        }
-        free(dev->pages);
-      }
-
       /* Close event channel and unmap shared page */
       mask_evtchn(dev->evtchn);
       unbind_evtchn(dev->evtchn);
       gnttab_end_access(dev->ring_ref);
 
-      free_page(dev->tx);
-
+      free_page(dev->page);
    }
 
    /* Cleanup memory usage */
@@ -387,13 +389,17 @@ void shutdown_tpmfront(struct tpmfront_dev* dev)
 
 int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length)
 {
+   unsigned int offset;
+   vtpm_shared_page_t* shr = NULL;
+#ifdef TPMFRONT_PRINT_DEBUG
    int i;
-   tpmif_tx_request_t* tx = NULL;
+#endif
    /* Error Checking */
    if(dev == NULL || dev->state != XenbusStateConnected) {
       TPMFRONT_ERR("Tried to send message through disconnected frontend\n");
       return -1;
    }
+   shr = dev->page;
 
 #ifdef TPMFRONT_PRINT_DEBUG
    TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length);
@@ -407,19 +413,16 @@ int tpmfront_send(struct tpmfront_dev* dev, const 
uint8_t* msg, size_t length)
 #endif
 
    /* Copy to shared pages now */
-   for(i = 0; length > 0 && i < TPMIF_TX_RING_SIZE; ++i) {
-      /* Share the page */
-      tx = &dev->tx->ring[i].req;
-      tx->unused = 0;
-      tx->addr = virt_to_mach(dev->pages[i]);
-      tx->ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->pages[i]), 
0);
-      /* Copy the bits to the page */
-      tx->size = length > PAGE_SIZE ? PAGE_SIZE : length;
-      memcpy(dev->pages[i], &msg[i * PAGE_SIZE], tx->size);
-
-      /* Update counters */
-      length -= tx->size;
+   offset = sizeof(*shr);
+   if (length + offset > PAGE_SIZE) {
+      TPMFRONT_ERR("Message too long for shared page\n");
+      return -1;
    }
+   memcpy(offset + (uint8_t*)shr, msg, length);
+   shr->length = length;
+   barrier();
+   shr->state = VTPM_STATE_SUBMIT;
+
    dev->waiting = 1;
    dev->resplen = 0;
 #ifdef HAVE_LIBC
@@ -429,49 +432,50 @@ int tpmfront_send(struct tpmfront_dev* dev, const 
uint8_t* msg, size_t length)
       files[dev->fd].tpmfront.offset = 0;
    }
 #endif
+   wmb();
    notify_remote_via_evtchn(dev->evtchn);
    return 0;
 }
 int tpmfront_recv(struct tpmfront_dev* dev, uint8_t** msg, size_t *length)
 {
-   tpmif_tx_request_t* tx;
-   int i;
+   unsigned int offset;
+   vtpm_shared_page_t* shr = NULL;
+#ifdef TPMFRONT_PRINT_DEBUG
+int i;
+#endif
    if(dev == NULL || dev->state != XenbusStateConnected) {
       TPMFRONT_ERR("Tried to receive message from disconnected frontend\n");
       return -1;
    }
    /*Wait for the response */
    wait_event(dev->waitq, (!dev->waiting));
+   shr = dev->page;
 
    /* Initialize */
    *msg = NULL;
    *length = 0;
+   offset = sizeof(*shr);
 
-   /* special case, just quit */
-   tx = &dev->tx->ring[0].req;
-   if(tx->size == 0 ) {
-       goto quit;
-   }
-   /* Get the total size */
-   tx = &dev->tx->ring[0].req;
-   for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) {
-      tx = &dev->tx->ring[i].req;
-      *length += tx->size;
+   if (shr->state != VTPM_STATE_FINISH)
+      goto quit;
+
+   *length = shr->length;
+
+   if (*length + offset > PAGE_SIZE) {
+      TPMFRONT_ERR("Reply too long for shared page\n");
+      return -1;
    }
+
    /* Alloc the buffer */
    if(dev->respbuf) {
       free(dev->respbuf);
    }
    *msg = dev->respbuf = malloc(*length);
    dev->resplen = *length;
+
    /* Copy the bits */
-   tx = &dev->tx->ring[0].req;
-   for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) {
-      tx = &dev->tx->ring[i].req;
-      memcpy(&(*msg)[i * PAGE_SIZE], dev->pages[i], tx->size);
-      gnttab_end_access(tx->ref);
-      tx->ref = 0;
-   }
+   memcpy(*msg, offset + (uint8_t*)shr, *length);
+
 #ifdef TPMFRONT_PRINT_DEBUG
    TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned int) 
*length);
    for(i = 0; i < *length; ++i) {
@@ -504,6 +508,14 @@ int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, 
size_t reqlen, uint8_t*
    return 0;
 }
 
+int tpmfront_set_locality(struct tpmfront_dev* dev, int locality)
+{
+   if (!dev || !dev->page)
+      return -1;
+   dev->page->locality = locality;
+   return 0;
+}
+
 #ifdef HAVE_LIBC
 #include <errno.h>
 int tpmfront_open(struct tpmfront_dev* dev)
diff --git a/xen/include/public/io/tpmif.h b/xen/include/public/io/tpmif.h
index fca2c4e..dcc5e57 100644
--- a/xen/include/public/io/tpmif.h
+++ b/xen/include/public/io/tpmif.h
@@ -64,6 +64,72 @@ struct tpmif_tx_interface {
 };
 typedef struct tpmif_tx_interface tpmif_tx_interface_t;
 
+/******************************************************************************
+ * TPM I/O interface for Xen guest OSes, v2
+ *
+ * Author: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
+ *
+ * This protocol emulates the request/response behavior of a TPM using a Xen
+ * shared memory interface. All interaction with the TPM is at the direction
+ * of the frontend, since a TPM (hardware or virtual) is a passive device -
+ * the backend only processes commands as requested by the frontend.
+ *
+ * The frontend sends a request to the TPM by populating the shared page with
+ * the request packet, changing the state to VTPM_STATE_SUBMIT, and sending
+ * and event channel notification. When the backend is finished, it will set
+ * the state to VTPM_STATE_FINISH and send an event channel notification.
+ *
+ * In order to allow long-running commands to be canceled, the frontend can
+ * at any time change the state to VTPM_STATE_CANCEL and send a notification.
+ * The TPM can either finish the command (changing state to VTPM_STATE_FINISH)
+ * or can cancel the command and change the state to VTPM_STATE_IDLE. The TPM
+ * can also change the state to VTPM_STATE_IDLE instead of VTPM_STATE_FINISH
+ * if another reason for cancellation is required - for example, a physical
+ * TPM may cancel a command if the interface is seized by another locality.
+ *
+ * The TPM command format is defined by the TCG, and is available at
+ * http://www.trustedcomputinggroup.org/resources/tpm_main_specification
+ */
+
+enum vtpm_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 */
+};
+/* Note: The backend should only change state to IDLE or FINISH, while the
+ * frontend should only change to SUBMIT or CANCEL. Status changes do not need
+ * to use atomic operations.
+ */
+
+
+/* The shared page for vTPM request/response packets looks like:
+ *
+ *  Offset               Contents
+ *  =================================================
+ *  0                    struct vtpm_shared_page
+ *  16                   [optional] List of grant IDs
+ *  16+4*nr_extra_pages  TPM packet data
+ *
+ * If the TPM packet data extends beyond the end of a single page, the grant 
IDs
+ * defined in extra_pages are used as if they were mapped immediately following
+ * the primary shared page. The grants are allocated by the frontend and mapped
+ * by the backend. Before sending a request spanning multiple pages, the
+ * frontend should verify that the TPM supports such large requests by querying
+ * the TPM_CAP_PROP_INPUT_BUFFER property from the TPM.
+ */
+struct vtpm_shared_page {
+    uint32_t length;         /* request/response length in bytes */
+
+    uint8_t state;           /* enum vtpm_state */
+    uint8_t locality;        /* for the current request */
+    uint8_t pad;             /* should be zero */
+
+    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 */
+};
+typedef struct vtpm_shared_page vtpm_shared_page_t;
+
 #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®.