All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
@ 2012-09-17 22:08 Matthew Fioravante
  2012-09-17 22:52 ` Samuel Thibault
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Matthew Fioravante @ 2012-09-17 22:08 UTC (permalink / raw)
  To: Samuel Thibault, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 105330 bytes --]

This patch adds 3 new drivers to mini-os.

tpmfront - paravirtualized tpm frontend driver
tpmback - paravirtualized tpm backend driver
tpm_tis - hardware tpm driver

Unfortunately these drivers were derived from GPL licensed linux kernel
drivers so they must carry the GPL license. However, since mini-os now
supports conditional compilation, hopefully these drivers can be
included into the xen tree and conditionally removed from non-gpl
projects. By default they are disabled in the makefile.

Signed off by: Matthew Fioravante matthew.fioravante@jhuapl.edu

diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -22,6 +22,9 @@ CONFIG_QEMU_XS_ARGS ?= n
 CONFIG_TEST ?= n
 CONFIG_PCIFRONT ?= n
 CONFIG_BLKFRONT ?= y
+CONFIG_TPMFRONT ?= n
+CONFIG_TPM_TIS ?= n
+CONFIG_TPMBACK ?= n
 CONFIG_NETFRONT ?= y
 CONFIG_FBFRONT ?= y
 CONFIG_KBDFRONT ?= y
@@ -36,6 +39,9 @@ flags-$(CONFIG_SPARSE_BSS) += -DCONFIG_SPARSE_BSS
 flags-$(CONFIG_QEMU_XS_ARGS) += -DCONFIG_QEMU_XS_ARGS
 flags-$(CONFIG_PCIFRONT) += -DCONFIG_PCIFRONT
 flags-$(CONFIG_BLKFRONT) += -DCONFIG_BLKFRONT
+flags-$(CONFIG_TPMFRONT) += -DCONFIG_TPMFRONT
+flags-$(CONFIG_TPM_TIS) += -DCONFIG_TPM_TIS
+flags-$(CONFIG_TPMBACK) += -DCONFIG_TPMBACK
 flags-$(CONFIG_NETFRONT) += -DCONFIG_NETFRONT
 flags-$(CONFIG_KBDFRONT) += -DCONFIG_KBDFRONT
 flags-$(CONFIG_FBFRONT) += -DCONFIG_FBFRONT
@@ -67,6 +73,9 @@ TARGET := mini-os
 SUBDIRS := lib xenbus console
 
 src-$(CONFIG_BLKFRONT) += blkfront.c
+src-$(CONFIG_TPMFRONT) += tpmfront.c
+src-$(CONFIG_TPM_TIS) += tpm_tis.c
+src-$(CONFIG_TPMBACK) += tpmback.c
 src-y += daytime.c
 src-y += events.c
 src-$(CONFIG_FBFRONT) += fbfront.c
diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h
--- a/extras/mini-os/include/lib.h
+++ b/extras/mini-os/include/lib.h
@@ -142,6 +142,8 @@ enum fd_type {
     FTYPE_FB,
     FTYPE_MEM,
     FTYPE_SAVEFILE,
+    FTYPE_TPMFRONT,
+    FTYPE_TPM_TIS,
 };
 
 LIST_HEAD(evtchn_port_list, evtchn_port_info);
@@ -185,6 +187,20 @@ extern struct file {
     struct {
         struct consfront_dev *dev;
     } cons;
+#ifdef CONFIG_TPMFRONT
+    struct {
+       struct tpmfront_dev *dev;
+       int respgot;
+       off_t offset;
+    } tpmfront;
+#endif
+#ifdef CONFIG_TPM_TIS
+    struct {
+       struct tpm_chip *dev;
+       int respgot;
+       off_t offset;
+    } tpm_tis;
+#endif
 #ifdef CONFIG_XENBUS
         struct {
             /* To each xenbus FD is associated a queue of watch events
for this
diff --git a/extras/mini-os/include/tpm_tis.h
b/extras/mini-os/include/tpm_tis.h
--- /dev/null
+++ b/extras/mini-os/include/tpm_tis.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This driver 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_tis.c
+ *  drivers/char/tpm/tpm.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#ifndef TPM_TIS_H
+#define TPM_TIS_H
+
+#include <mini-os/types.h>
+#include <mini-os/byteorder.h>
+
+#define TPM_TIS_EN_LOCL0 1
+#define TPM_TIS_EN_LOCL1 (1 << 1)
+#define TPM_TIS_EN_LOCL2 (1 << 2)
+#define TPM_TIS_EN_LOCL3 (1 << 3)
+#define TPM_TIS_EN_LOCL4 (1 << 4)
+#define TPM_TIS_EN_LOCLALL (TPM_TIS_EN_LOCL0 | TPM_TIS_EN_LOCL1  |
TPM_TIS_EN_LOCL2 | TPM_TIS_EN_LOCL3 | TPM_TIS_EN_LOCL4)
+#define TPM_TIS_LOCL_INT_TO_FLAG(x) (1 << x)
+#define TPM_BASEADDR 0xFED40000
+#define TPM_PROBE_IRQ 0xFFFF
+
+struct tpm_chip;
+
+struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
unsigned int irq);
+void shutdown_tpm_tis(struct tpm_chip* tpm);
+
+int tpm_tis_request_locality(struct tpm_chip* tpm, int locality);
+int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen);
+
+#ifdef HAVE_LIBC
+#include <sys/stat.h>
+#include <fcntl.h>
+/* POSIX IO functions:
+ * use tpm_tis_open() to get a file descriptor to the tpm device
+ * use write() on the fd to send a command to the backend. You must
+ * include the entire command in a single call to write().
+ * use read() on the fd to read the response. You can use
+ * fstat() to get the size of the response and lseek() to seek on it.
+ */
+int tpm_tis_open(struct tpm_chip* tpm);
+int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count);
+int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count);
+int tpm_tis_posix_fstat(int fd, struct stat* buf);
+#endif
+
+#endif
diff --git a/extras/mini-os/include/tpmback.h
b/extras/mini-os/include/tpmback.h
--- /dev/null
+++ b/extras/mini-os/include/tpmback.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This driver 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based upon the files:
+ *  drivers/xen/tpmbk.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <xen/io/tpmif.h>
+#include <xen/io/xenbus.h>
+#include <mini-os/types.h>
+#include <xen/xen.h>
+#ifndef TPMBACK_H
+#define TPMBACK_H
+
+struct tpmcmd {
+   domid_t domid;        /* Domid of the frontend */
+   unsigned int handle;    /* Handle of the frontend */
+   char* uuid;            /* uuid of the tpm interface - allocated
internally, dont free it */
+
+   unsigned int req_len;        /* Size of the command in buf - set by
tpmback driver */
+   uint8_t* req;            /* tpm command bits, allocated by driver,
DON'T FREE IT */
+   unsigned int resp_len;    /* Size of the outgoing command,
+                   you set this before passing the cmd object to
tpmback_resp */
+   uint8_t* resp;        /* Buffer for response - YOU MUST ALLOCATE IT,
YOU MUST ALSO FREE IT */
+};
+typedef struct tpmcmd tpmcmd_t;
+
+/* Initialize the tpm backend driver
+ * @exclusive_domname - This is NULL terminated list of vtpm uuid
strings. If this list
+ *             is non-empty, then only frontend domains with vtpm
uuid's matching
+ *             entries in this list will be allowed to connect.
+ *             Other connections will be immediatly closed.
+ *             Set this argument to NULL to allow any vtpm to connect.
+ */
+void init_tpmback(char** exclusive_uuids);
+/* Shutdown tpm backend driver */
+void shutdown_tpmback(void);
+
+/* Blocks until a tpm command is sent from any front end.
+ * Returns a pointer to the tpm command to handle.
+ * Do not try to free this pointer or the req buffer
+ * This function will return NULL if the tpm backend driver
+ * is shutdown or any other error occurs */
+tpmcmd_t* tpmback_req_any(void);
+
+/* Blocks until a tpm command from the frontend at domid/handle
+ * is sent.
+ * Returns NULL if domid/handle is not connected, tpmback is
+ * shutdown or shutting down, or if there is an error
+ */
+tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle);
+
+/* Send the response to the tpm command back to the frontend
+ * This function will free the tpmcmd object, but you must free the resp
+ * buffer yourself */
+void tpmback_resp(tpmcmd_t* tpmcmd);
+
+/* Waits for the first frontend to connect and then sets domid and
handle appropriately.
+ * If one or more frontends are already connected, this will set domid
and handle to one
+ * of them arbitrarily. The main use for this function is to wait until
a single
+ * frontend connection has occured.
+ * returns 0 on success, non-zero on failure */
+int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int
*handle);
+
+/* returns the number of frontends connected */
+int tpmback_num_frontends(void);
+
+/* Returns the uuid of the specified frontend, NULL on error */
+char* tpmback_get_uuid(domid_t domid, unsigned int handle);
+
+/* Specify a function to call when a new tpm device connects */
+void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int));
+
+/* Specify a function to call when a tpm device disconnects */
+void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int));
+
+//Not Implemented
+void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int));
+void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int));
+
+#endif
diff --git a/extras/mini-os/include/tpmfront.h
b/extras/mini-os/include/tpmfront.h
--- /dev/null
+++ b/extras/mini-os/include/tpmfront.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This driver 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_vtpm.c
+ *  drivers/char/tpm/tpm_xen.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#ifndef TPMFRONT_H
+#define TPMFRONT_H
+
+#include <mini-os/types.h>
+#include <mini-os/os.h>
+#include <mini-os/events.h>
+#include <mini-os/wait.h>
+#include <xen/xen.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/tpmif.h>
+
+struct tpmfront_dev {
+   grant_ref_t ring_ref;
+   evtchn_port_t evtchn;
+
+   tpmif_tx_interface_t* tx;
+
+   void** pages;
+
+   domid_t bedomid;
+   char* nodename;
+   char* bepath;
+
+   XenbusState state;
+
+   uint8_t waiting;
+   struct wait_queue_head waitq;
+
+   uint8_t* respbuf;
+   size_t resplen;
+
+#ifdef HAVE_LIBC
+   int fd;
+#endif
+
+};
+
+
+/*Initialize frontend */
+struct tpmfront_dev* init_tpmfront(const char* nodename);
+/*Shutdown frontend */
+void shutdown_tpmfront(struct tpmfront_dev* dev);
+
+/* Send a tpm command to the backend and wait for the response
+ *
+ * @dev - frontend device
+ * @req - request buffer
+ * @reqlen - length of request buffer
+ * @resp - *resp will be set to internal response buffer, don't free
it! Value is undefined on error
+ * @resplen - *resplen will be set to the length of the response. Value
is undefined on error
+ *
+ * returns 0 on success, non zero on failure.
+ * */
+int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen);
+
+#ifdef HAVE_LIBC
+#include <sys/stat.h>
+/* POSIX IO functions:
+ * use tpmfront_open() to get a file descriptor to the tpm device
+ * use write() on the fd to send a command to the backend. You must
+ * include the entire command in a single call to write().
+ * use read() on the fd to read the response. You can use
+ * fstat() to get the size of the response and lseek() to seek on it.
+ */
+int tpmfront_open(struct tpmfront_dev* dev);
+int tpmfront_posix_read(int fd, uint8_t* buf, size_t count);
+int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count);
+int tpmfront_posix_fstat(int fd, struct stat* buf);
+#endif
+
+
+#endif
diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
--- a/extras/mini-os/lib/sys.c
+++ b/extras/mini-os/lib/sys.c
@@ -27,6 +27,8 @@
 #include <netfront.h>
 #include <blkfront.h>
 #include <fbfront.h>
+#include <tpmfront.h>
+#include <tpm_tis.h>
 #include <xenbus.h>
 #include <xenstore.h>
 
@@ -294,6 +296,16 @@ int read(int fd, void *buf, size_t nbytes)
         return blkfront_posix_read(fd, buf, nbytes);
         }
 #endif
+#ifdef CONFIG_TPMFRONT
+        case FTYPE_TPMFRONT: {
+        return tpmfront_posix_read(fd, buf, nbytes);
+        }
+#endif
+#ifdef CONFIG_TPM_TIS
+        case FTYPE_TPM_TIS: {
+        return tpm_tis_posix_read(fd, buf, nbytes);
+        }
+#endif
     default:
         break;
     }
@@ -330,6 +342,14 @@ int write(int fd, const void *buf, size_t nbytes)
     case FTYPE_BLK:
         return blkfront_posix_write(fd, buf, nbytes);
 #endif
+#ifdef CONFIG_TPMFRONT
+    case FTYPE_TPMFRONT:
+        return tpmfront_posix_write(fd, buf, nbytes);
+#endif
+#ifdef CONFIG_TPM_TIS
+    case FTYPE_TPM_TIS:
+        return tpm_tis_posix_write(fd, buf, nbytes);
+#endif
     default:
         break;
     }
@@ -341,8 +361,16 @@ int write(int fd, const void *buf, size_t nbytes)
 off_t lseek(int fd, off_t offset, int whence)
 {
     switch(files[fd].type) {
+#if defined(CONFIG_BLKFRONT) || defined(CONFIG_TPMFRONT) ||
defined(CONFIG_TPM_TIS)
 #ifdef CONFIG_BLKFRONT
        case FTYPE_BLK:
+#endif
+#ifdef CONFIG_TPMFRNT
+       case FTYPE_TPMFRONT:
+#endif
+#ifdef CONFIG_TPM_TIS
+       case FTYPE_TPM_TIS:
+#endif
       switch (whence) {
          case SEEK_SET:
         files[fd].file.offset = offset;
@@ -420,6 +448,18 @@ int close(int fd)
         files[fd].type = FTYPE_NONE;
         return 0;
 #endif
+#ifdef CONFIG_TPMFRONT
+    case FTYPE_TPMFRONT:
+            shutdown_tpmfront(files[fd].tpmfront.dev);
+        files[fd].type = FTYPE_NONE;
+        return 0;
+#endif
+#ifdef CONFIG_TPM_TIS
+    case FTYPE_TPM_TIS:
+            shutdown_tpm_tis(files[fd].tpm_tis.dev);
+        files[fd].type = FTYPE_NONE;
+        return 0;
+#endif
 #ifdef CONFIG_KBDFRONT
     case FTYPE_KBD:
             shutdown_kbdfront(files[fd].kbd.dev);
@@ -489,6 +529,14 @@ int fstat(int fd, struct stat *buf)
     case FTYPE_BLK:
        return blkfront_posix_fstat(fd, buf);
 #endif
+#ifdef CONFIG_TPMFRONT
+    case FTYPE_TPMFRONT:
+       return tpmfront_posix_fstat(fd, buf);
+#endif
+#ifdef CONFIG_TPM_TIS
+    case FTYPE_TPM_TIS:
+       return tpm_tis_posix_fstat(fd, buf);
+#endif
     default:
         break;
     }
diff --git a/extras/mini-os/tpm_tis.c b/extras/mini-os/tpm_tis.c
--- /dev/null
+++ b/extras/mini-os/tpm_tis.c
@@ -0,0 +1,1344 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This driver 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_tis.c
+ *  drivers/char/tpm/tpm.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <mini-os/ioremap.h>
+#include <mini-os/iorw.h>
+#include <mini-os/tpm_tis.h>
+#include <mini-os/os.h>
+#include <mini-os/sched.h>
+#include <mini-os/byteorder.h>
+#include <mini-os/events.h>
+#include <mini-os/wait.h>
+#include <mini-os/xmalloc.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#ifndef min
+    #define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
+#endif
+
+#define TPM_HEADER_SIZE 10
+
+#define TPM_BUFSIZE 2048
+
+struct tpm_input_header {
+        uint16_t  tag;
+        uint32_t  length;
+        uint32_t  ordinal;
+}__attribute__((packed));
+
+struct tpm_output_header {
+        uint16_t  tag;
+        uint32_t  length;
+        uint32_t  return_code;
+}__attribute__((packed));
+
+struct  stclear_flags_t {
+        uint16_t  tag;
+        uint8_t      deactivated;
+        uint8_t      disableForceClear;
+        uint8_t      physicalPresence;
+        uint8_t      physicalPresenceLock;
+        uint8_t      bGlobalLock;
+}__attribute__((packed));
+
+struct  tpm_version_t {
+        uint8_t      Major;
+        uint8_t      Minor;
+        uint8_t      revMajor;
+        uint8_t      revMinor;
+}__attribute__((packed));
+
+struct  tpm_version_1_2_t {
+        uint16_t  tag;
+        uint8_t      Major;
+        uint8_t      Minor;
+        uint8_t      revMajor;
+        uint8_t      revMinor;
+}__attribute__((packed));
+
+struct  timeout_t {
+        uint32_t  a;
+        uint32_t  b;
+        uint32_t  c;
+        uint32_t  d;
+}__attribute__((packed));
+
+struct duration_t {
+        uint32_t  tpm_short;
+        uint32_t  tpm_medium;
+        uint32_t  tpm_long;
+}__attribute__((packed));
+
+struct permanent_flags_t {
+        uint16_t  tag;
+        uint8_t      disable;
+        uint8_t      ownership;
+        uint8_t      deactivated;
+        uint8_t      readPubek;
+        uint8_t      disableOwnerClear;
+        uint8_t      allowMaintenance;
+        uint8_t      physicalPresenceLifetimeLock;
+        uint8_t      physicalPresenceHWEnable;
+        uint8_t      physicalPresenceCMDEnable;
+        uint8_t      CEKPUsed;
+        uint8_t      TPMpost;
+        uint8_t      TPMpostLock;
+        uint8_t      FIPS;
+        uint8_t      operator;
+        uint8_t      enableRevokeEK;
+        uint8_t      nvLocked;
+        uint8_t      readSRKPub;
+        uint8_t      tpmEstablished;
+        uint8_t      maintenanceDone;
+        uint8_t      disableFullDALogicInfo;
+}__attribute__((packed));
+
+typedef union {
+        struct  permanent_flags_t perm_flags;
+        struct  stclear_flags_t stclear_flags;
+        bool    owned;
+        uint32_t  num_pcrs;
+        struct  tpm_version_t   tpm_version;
+        struct  tpm_version_1_2_t tpm_version_1_2;
+        uint32_t  manufacturer_id;
+        struct timeout_t  timeout;
+        struct duration_t duration;
+} cap_t;
+
+struct  tpm_getcap_params_in {
+        uint32_t  cap;
+        uint32_t  subcap_size;
+        uint32_t  subcap;
+}__attribute__((packed));
+
+struct  tpm_getcap_params_out {
+        uint32_t  cap_size;
+        cap_t   cap;
+}__attribute__((packed));
+
+struct  tpm_readpubek_params_out {
+        uint8_t      algorithm[4];
+        uint8_t      encscheme[2];
+        uint8_t      sigscheme[2];
+        uint32_t  paramsize;
+        uint8_t      parameters[12]; /*assuming RSA*/
+        uint32_t  keysize;
+        uint8_t      modulus[256];
+        uint8_t      checksum[20];
+}__attribute__((packed));
+
+typedef union {
+        struct  tpm_input_header in;
+        struct  tpm_output_header out;
+} tpm_cmd_header;
+
+#define TPM_DIGEST_SIZE 20
+struct tpm_pcrread_out {
+        uint8_t      pcr_result[TPM_DIGEST_SIZE];
+}__attribute__((packed));
+
+struct tpm_pcrread_in {
+        uint32_t  pcr_idx;
+}__attribute__((packed));
+
+struct tpm_pcrextend_in {
+        uint32_t  pcr_idx;
+        uint8_t      hash[TPM_DIGEST_SIZE];
+}__attribute__((packed));
+
+typedef union {
+        struct  tpm_getcap_params_out getcap_out;
+        struct  tpm_readpubek_params_out readpubek_out;
+        uint8_t      readpubek_out_buffer[sizeof(struct
tpm_readpubek_params_out)];
+        struct  tpm_getcap_params_in getcap_in;
+        struct  tpm_pcrread_in  pcrread_in;
+        struct  tpm_pcrread_out pcrread_out;
+        struct  tpm_pcrextend_in pcrextend_in;
+} tpm_cmd_params;
+
+struct tpm_cmd_t {
+        tpm_cmd_header  header;
+        tpm_cmd_params  params;
+}__attribute__((packed));
+
+
+enum tpm_duration {
+   TPM_SHORT = 0,
+   TPM_MEDIUM = 1,
+   TPM_LONG = 2,
+   TPM_UNDEFINED,
+};
+
+#define TPM_MAX_ORDINAL 243
+#define TPM_MAX_PROTECTED_ORDINAL 12
+#define TPM_PROTECTED_ORDINAL_MASK 0xFF
+
+extern const uint8_t
tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL];
+extern const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL];
+
+#define TPM_DIGEST_SIZE 20
+#define TPM_ERROR_SIZE 10
+#define TPM_RET_CODE_IDX 6
+
+/* tpm_capabilities */
+#define TPM_CAP_FLAG cpu_to_be32(4)
+#define TPM_CAP_PROP cpu_to_be32(5)
+#define CAP_VERSION_1_1 cpu_to_be32(0x06)
+#define CAP_VERSION_1_2 cpu_to_be32(0x1A)
+
+/* tpm_sub_capabilities */
+#define TPM_CAP_PROP_PCR cpu_to_be32(0x101)
+#define TPM_CAP_PROP_MANUFACTURER cpu_to_be32(0x103)
+#define TPM_CAP_FLAG_PERM cpu_to_be32(0x108)
+#define TPM_CAP_FLAG_VOL cpu_to_be32(0x109)
+#define TPM_CAP_PROP_OWNER cpu_to_be32(0x111)
+#define TPM_CAP_PROP_TIS_TIMEOUT cpu_to_be32(0x115)
+#define TPM_CAP_PROP_TIS_DURATION cpu_to_be32(0x120)
+
+
+#define TPM_INTERNAL_RESULT_SIZE 200
+#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
+#define TPM_ORD_GET_CAP cpu_to_be32(101)
+
+extern const struct tpm_input_header tpm_getcap_header;
+
+
+
+const uint8_t tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
+   TPM_UNDEFINED,          /* 0 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 5 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 10 */
+   TPM_SHORT,
+};
+
+const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
+   TPM_UNDEFINED,          /* 0 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 5 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 10 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_LONG,
+   TPM_LONG,
+   TPM_MEDIUM,             /* 15 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_LONG,
+   TPM_SHORT,              /* 20 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_SHORT,              /* 25 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,             /* 30 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 35 */
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 40 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 45 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_LONG,
+   TPM_MEDIUM,             /* 50 */
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 55 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 60 */
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,             /* 65 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 70 */
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 75 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_LONG,               /* 80 */
+   TPM_UNDEFINED,
+   TPM_MEDIUM,
+   TPM_LONG,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 85 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 90 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 95 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 100 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 105 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 110 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 115 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_LONG,               /* 120 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_SHORT,              /* 125 */
+   TPM_SHORT,
+   TPM_LONG,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 130 */
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,          /* 135 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 140 */
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 145 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 150 */
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 155 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 160 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 165 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_LONG,               /* 170 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 175 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 180 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,             /* 185 */
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 190 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 195 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 200 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_SHORT,              /* 205 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,             /* 210 */
+   TPM_UNDEFINED,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,          /* 215 */
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_SHORT,              /* 220 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 225 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 230 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 235 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 240 */
+   TPM_UNDEFINED,
+   TPM_MEDIUM,
+};
+
+const struct tpm_input_header tpm_getcap_header = {
+        .tag = TPM_TAG_RQU_COMMAND,
+        .length = cpu_to_be32(22),
+        .ordinal = TPM_ORD_GET_CAP
+};
+
+
+enum tis_access {
+   TPM_ACCESS_VALID = 0x80,
+   TPM_ACCESS_ACTIVE_LOCALITY = 0x20,    /* (R) */
+   TPM_ACCESS_RELINQUISH_LOCALITY = 0x20,/* (W) */
+   TPM_ACCESS_REQUEST_PENDING = 0x04,    /* (W) */
+   TPM_ACCESS_REQUEST_USE = 0x02,    /* (W) */
+};
+
+enum tis_status {
+   TPM_STS_VALID = 0x80,        /* (R) */
+   TPM_STS_COMMAND_READY = 0x40,    /* (R) */
+   TPM_STS_DATA_AVAIL = 0x10,        /* (R) */
+   TPM_STS_DATA_EXPECT = 0x08,        /* (R) */
+   TPM_STS_GO = 0x20,            /* (W) */
+};
+
+enum tis_int_flags {
+   TPM_GLOBAL_INT_ENABLE = 0x80000000,
+   TPM_INTF_BURST_COUNT_STATIC = 0x100,
+   TPM_INTF_CMD_READY_INT = 0x080,
+   TPM_INTF_INT_EDGE_FALLING = 0x040,
+   TPM_INTF_INT_EDGE_RISING = 0x020,
+   TPM_INTF_INT_LEVEL_LOW = 0x010,
+   TPM_INTF_INT_LEVEL_HIGH = 0x008,
+   TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
+   TPM_INTF_STS_VALID_INT = 0x002,
+   TPM_INTF_DATA_AVAIL_INT = 0x001,
+};
+
+enum tis_defaults {
+   TIS_MEM_BASE = 0xFED40000,
+   TIS_MEM_LEN  = 0x5000,
+   TIS_SHORT_TIMEOUT = 750, /*ms*/
+   TIS_LONG_TIMEOUT = 2000, /*2 sec */
+};
+
+#define TPM_TIMEOUT 5
+
+#define TPM_ACCESS(t, l)                   (((uint8_t*)t->pages[l]) +
0x0000)
+#define TPM_INT_ENABLE(t, l)              
((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0008))
+#define TPM_INT_VECTOR(t, l)               (((uint8_t*)t->pages[l]) +
0x000C)
+#define TPM_INT_STATUS(t, l)               (((uint8_t*)t->pages[l]) +
0x0010)
+#define TPM_INTF_CAPS(t, l)               
((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0014))
+#define TPM_STS(t, l)                     
((uint8_t*)(((uint8_t*)t->pages[l]) + 0x0018))
+#define TPM_DATA_FIFO(t, l)                (((uint8_t*)t->pages[l]) +
0x0024)
+
+#define TPM_DID_VID(t, l)                 
((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0F00))
+#define TPM_RID(t, l)                      (((uint8_t*)t->pages[l]) +
0x0F04)
+
+struct tpm_chip {
+   int enabled_localities;
+   int locality;
+   unsigned long baseaddr;
+   uint8_t* pages[5];
+   int did, vid, rid;
+
+   uint8_t data_buffer[TPM_BUFSIZE];
+   int data_len;
+
+   s_time_t timeout_a, timeout_b, timeout_c, timeout_d;
+   s_time_t duration[3];
+
+#ifdef HAVE_LIBC
+   int fd;
+#endif
+
+   unsigned int irq;
+   struct wait_queue_head read_queue;
+   struct wait_queue_head int_queue;
+};
+
+
+static void __init_tpm_chip(struct tpm_chip* tpm) {
+   tpm->enabled_localities = TPM_TIS_EN_LOCLALL;
+   tpm->locality = -1;
+   tpm->baseaddr = 0;
+   tpm->pages[0] = tpm->pages[1] = tpm->pages[2] = tpm->pages[3] =
tpm->pages[4] = NULL;
+   tpm->vid = 0;
+   tpm->did = 0;
+   tpm->irq = 0;
+   init_waitqueue_head(&tpm->read_queue);
+   init_waitqueue_head(&tpm->int_queue);
+
+   tpm->data_len = -1;
+
+#ifdef HAVE_LIBC
+   tpm->fd = -1;
+#endif
+}
+
+/*
+ * Returns max number of nsecs to wait
+ */
+s_time_t tpm_calc_ordinal_duration(struct tpm_chip *chip,
+      uint32_t ordinal)
+{
+   int duration_idx = TPM_UNDEFINED;
+   s_time_t duration = 0;
+
+   if (ordinal < TPM_MAX_ORDINAL)
+      duration_idx = tpm_ordinal_duration[ordinal];
+   else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
+     TPM_MAX_PROTECTED_ORDINAL)
+      duration_idx =
+     tpm_protected_ordinal_duration[ordinal &
+     TPM_PROTECTED_ORDINAL_MASK];
+
+   if (duration_idx != TPM_UNDEFINED) {
+      duration = chip->duration[duration_idx];
+   }
+
+   if (duration <= 0) {
+      return SECONDS(120);
+   }
+   else
+   {
+      return duration;
+   }
+}
+
+
+static int locality_enabled(struct tpm_chip* tpm, int l) {
+   return tpm->enabled_localities & (1 << l);
+}
+
+static int check_locality(struct tpm_chip* tpm, int l) {
+   if(locality_enabled(tpm, l) && (ioread8(TPM_ACCESS(tpm, l)) &
+        (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
+     (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
+      return l;
+   }
+   return -1;
+}
+
+void release_locality(struct tpm_chip* tpm, int l, int force)
+{
+   if (locality_enabled(tpm, l) && (force || (ioread8(TPM_ACCESS(tpm, l)) &
+           (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
+        (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))) {
+      iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_RELINQUISH_LOCALITY);
+   }
+}
+
+int tpm_tis_request_locality(struct tpm_chip* tpm, int l) {
+
+   s_time_t stop;
+   /*Make sure locality is valid */
+   if(!locality_enabled(tpm, l)) {
+      printk("tpm_tis_change_locality() Tried to change to locality %d,
but it is disabled or invalid!\n", l);
+      return -1;
+   }
+   /* Check if we already have the current locality */
+   if(check_locality(tpm, l) >= 0) {
+      return tpm->locality = l;
+   }
+   /* Set the new locality*/
+   iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_REQUEST_USE);
+
+   if(tpm->irq) {
+      /* Wait for interrupt */
+      wait_event_deadline(tpm->int_queue, (check_locality(tpm, l) >=
0), NOW() + tpm->timeout_a);
+
+      /* FIXME: Handle timeout event, should return error in that case */
+      return l;
+   } else {
+      /* Wait for burstcount */
+      stop = NOW() + tpm->timeout_a;
+      do {
+     if(check_locality(tpm, l) >= 0) {
+        return tpm->locality = l;
+     }
+     msleep(TPM_TIMEOUT);
+      } while(NOW() < stop);
+   }
+
+   printk("REQ LOCALITY FAILURE\n");
+   return -1;
+}
+
+static uint8_t tpm_tis_status(struct tpm_chip* tpm) {
+   return ioread8(TPM_STS(tpm, tpm->locality));
+}
+
+/* This causes the current command to be aborted */
+static void tpm_tis_ready(struct tpm_chip* tpm) {
+   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_COMMAND_READY);
+}
+#define tpm_tis_cancel_cmd(v) tpm_tis_ready(v)
+
+static int get_burstcount(struct tpm_chip* tpm) {
+   s_time_t stop;
+   int burstcnt;
+
+   stop = NOW() + tpm->timeout_d;
+   do {
+      burstcnt = ioread8((TPM_STS(tpm, tpm->locality) + 1));
+      burstcnt += ioread8(TPM_STS(tpm, tpm->locality) + 2) << 8;
+
+      if (burstcnt) {
+     return burstcnt;
+      }
+      msleep(TPM_TIMEOUT);
+   } while(NOW() < stop);
+   return -EBUSY;
+}
+
+static int wait_for_stat(struct tpm_chip* tpm, uint8_t mask,
+      unsigned long timeout, struct wait_queue_head* queue) {
+   s_time_t stop;
+   uint8_t status;
+
+   status = tpm_tis_status(tpm);
+   if((status & mask) == mask) {
+      return 0;
+   }
+
+   if(tpm->irq) {
+      wait_event_deadline(*queue, ((tpm_tis_status(tpm) & mask) ==
mask), timeout);
+      /* FIXME: Check for timeout and return -ETIME */
+      return 0;
+   } else {
+      stop = NOW() + timeout;
+      do {
+     msleep(TPM_TIMEOUT);
+     status = tpm_tis_status(tpm);
+     if((status & mask) == mask)
+        return 0;
+      } while( NOW() < stop);
+   }
+   return -ETIME;
+}
+
+static int recv_data(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
+   int size = 0;
+   int burstcnt;
+   while( size < count &&
+     wait_for_stat(tpm,
+        TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+        tpm->timeout_c,
+        &tpm->read_queue)
+     == 0) {
+      burstcnt = get_burstcount(tpm);
+      for(; burstcnt > 0 && size < count; --burstcnt)
+      {
+     buf[size++] = ioread8(TPM_DATA_FIFO(tpm, tpm->locality));
+      }
+   }
+   return size;
+}
+
+int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
+   int size = 0;
+   int expected, status;
+
+   if (count < TPM_HEADER_SIZE) {
+      size = -EIO;
+      goto out;
+   }
+
+   /* read first 10 bytes, including tag, paramsize, and result */
+   if((size =
+        recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
+      printk("Error reading tpm cmd header\n");
+      goto out;
+   }
+
+   expected = be32_to_cpu(*((uint32_t*)(buf + 2)));
+   if(expected > count) {
+      size = -EIO;
+      goto out;
+   }
+
+   if((size += recv_data(tpm, & buf[TPM_HEADER_SIZE],
+           expected - TPM_HEADER_SIZE)) < expected) {
+      printk("Unable to read rest of tpm command size=%d
expected=%d\n", size, expected);
+      size = -ETIME;
+      goto out;
+   }
+
+   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
+   status = tpm_tis_status(tpm);
+   if(status & TPM_STS_DATA_AVAIL) {
+      printk("Error: left over data\n");
+      size = -EIO;
+      goto out;
+   }
+
+out:
+   tpm_tis_ready(tpm);
+   release_locality(tpm, tpm->locality, 0);
+   return size;
+}
+int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) {
+   int rc;
+   int status, burstcnt = 0;
+   int count = 0;
+   uint32_t ordinal;
+
+   if(tpm_tis_request_locality(tpm, tpm->locality) < 0) {
+      return -EBUSY;
+   }
+
+   status = tpm_tis_status(tpm);
+   if((status & TPM_STS_COMMAND_READY) == 0) {
+      tpm_tis_ready(tpm);
+      if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b,
&tpm->int_queue) < 0) {
+     rc = -ETIME;
+     goto out_err;
+      }
+   }
+
+   while(count < len - 1) {
+      burstcnt = get_burstcount(tpm);
+      for(;burstcnt > 0 && count < len -1; --burstcnt) {
+     iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]);
+      }
+
+      wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
+      status = tpm_tis_status(tpm);
+      if((status & TPM_STS_DATA_EXPECT) == 0) {
+     rc = -EIO;
+     goto out_err;
+      }
+   }
+
+   /*Write last byte*/
+   iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]);
+   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue);
+   status = tpm_tis_status(tpm);
+   if((status & TPM_STS_DATA_EXPECT) != 0) {
+      rc = -EIO;
+      goto out_err;
+   }
+
+   /*go and do it*/
+   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO);
+
+   if(tpm->irq) {
+      /*Wait for interrupt */
+      ordinal = be32_to_cpu(*(buf + 6));
+      if(wait_for_stat(tpm,
+           TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+           tpm_calc_ordinal_duration(tpm, ordinal),
+           &tpm->read_queue) < 0) {
+     rc = -ETIME;
+     goto out_err;
+      }
+   }
+#ifdef HAVE_LIBC
+   if(tpm->fd >= 0) {
+      files[tpm->fd].read = 0;
+      files[tpm->fd].tpm_tis.respgot = 0;
+      files[tpm->fd].tpm_tis.offset = 0;
+   }
+#endif
+   return len;
+
+out_err:
+   tpm_tis_ready(tpm);
+   release_locality(tpm, tpm->locality, 0);
+   return rc;
+}
+
+static void tpm_tis_irq_handler(evtchn_port_t port, struct pt_regs
*regs, void* data)
+{
+   struct tpm_chip* tpm = data;
+   uint32_t interrupt;
+   int i;
+
+   interrupt = ioread32(TPM_INT_STATUS(tpm, tpm->locality));
+   if(interrupt == 0) {
+      return;
+   }
+
+   if(interrupt & TPM_INTF_DATA_AVAIL_INT) {
+      wake_up(&tpm->read_queue);
+   }
+   if(interrupt & TPM_INTF_LOCALITY_CHANGE_INT) {
+      for(i = 0; i < 5; ++i) {
+     if(check_locality(tpm, i) >= 0) {
+        break;
+     }
+      }
+   }
+   if(interrupt & (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
+        TPM_INTF_CMD_READY_INT)) {
+      wake_up(&tpm->int_queue);
+   }
+
+   /* Clear interrupts handled with TPM_EOI */
+   iowrite32(TPM_INT_STATUS(tpm, tpm->locality), interrupt);
+   ioread32(TPM_INT_STATUS(tpm, tpm->locality));
+   return;
+}
+
+/*
+ * Internal kernel interface to transmit TPM commands
+ */
+static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf,
+      size_t bufsiz)
+{
+   ssize_t rc;
+   uint32_t count, ordinal;
+   s_time_t stop;
+
+   count = be32_to_cpu(*((uint32_t *) (buf + 2)));
+   ordinal = be32_to_cpu(*((uint32_t *) (buf + 6)));
+   if (count == 0)
+      return -ENODATA;
+   if (count > bufsiz) {
+      printk("Error: invalid count value %x %zx \n", count, bufsiz);
+      return -E2BIG;
+   }
+
+   //down(&chip->tpm_mutex);
+
+   if ((rc = tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) {
+      printk("tpm_transmit: tpm_send: error %zd\n", rc);
+      goto out;
+   }
+
+   if (chip->irq)
+      goto out_recv;
+
+   stop = NOW() + tpm_calc_ordinal_duration(chip, ordinal);
+   do {
+      uint8_t status = tpm_tis_status(chip);
+      if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) ==
+        (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
+     goto out_recv;
+
+      if ((status == TPM_STS_COMMAND_READY)) {
+     printk("TPM Error: Operation Canceled\n");
+     rc = -ECANCELED;
+     goto out;
+      }
+
+      msleep(TPM_TIMEOUT);    /* CHECK */
+      rmb();
+   } while (NOW() < stop);
+
+   /* Cancel the command */
+   tpm_tis_cancel_cmd(chip);
+   printk("TPM Operation Timed out\n");
+   rc = -ETIME;
+   goto out;
+
+out_recv:
+   if((rc = tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) {
+      printk("tpm_transmit: tpm_recv: error %d\n", rc);
+   }
+out:
+   //up(&chip->tpm_mutex);
+   return rc;
+}
+
+static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
+                            int len, const char *desc)
+{
+        int err;
+
+        len = tpm_transmit(chip,(uint8_t *) cmd, len);
+        if (len <  0)
+                return len;
+        if (len == TPM_ERROR_SIZE) {
+                err = be32_to_cpu(cmd->header.out.return_code);
+                printk("A TPM error (%d) occurred %s\n", err, desc);
+                return err;
+        }
+        return 0;
+}
+
+void tpm_get_timeouts(struct tpm_chip *chip)
+{
+   struct tpm_cmd_t tpm_cmd;
+   struct timeout_t *timeout_cap;
+   struct duration_t *duration_cap;
+   ssize_t rc;
+   uint32_t timeout;
+
+   tpm_cmd.header.in = tpm_getcap_header;
+   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+
+   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+     "attempting to determine the timeouts")) != 0) {
+      printk("transmit failed %d\n", rc);
+      goto duration;
+   }
+
+   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
+     != 4 * sizeof(uint32_t)) {
+      printk("Out len check failure %lu \n",
be32_to_cpu(tpm_cmd.header.out.length));
+      goto duration;
+   }
+
+   timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
+   /* Don't overwrite default if value is 0 */
+   timeout = be32_to_cpu(timeout_cap->a);
+   if (timeout)
+      chip->timeout_a = MICROSECS(timeout); /*Convert to msec */
+   timeout = be32_to_cpu(timeout_cap->b);
+   if (timeout)
+      chip->timeout_b = MICROSECS(timeout); /*Convert to msec */
+   timeout = be32_to_cpu(timeout_cap->c);
+   if (timeout)
+      chip->timeout_c = MICROSECS(timeout); /*Convert to msec */
+   timeout = be32_to_cpu(timeout_cap->d);
+   if (timeout)
+      chip->timeout_d = MICROSECS(timeout); /*Convert to msec */
+
+duration:
+   tpm_cmd.header.in = tpm_getcap_header;
+   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
+
+   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+     "attempting to determine the durations")) < 0) {
+      return;
+   }
+
+   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
+     != 3 * sizeof(uint32_t)) {
+      return;
+   }
+        duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
+        chip->duration[TPM_SHORT] = be32_to_cpu(duration_cap->tpm_short);
+        /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets
the above
+         * value wrong and apparently reports msecs rather than usecs.
So we
+         * fix up the resulting too-small TPM_SHORT value to make
things work.
+         */
+        if (chip->duration[TPM_SHORT] < 10) {
+       chip->duration[TPM_SHORT] = MILLISECS(chip->duration[TPM_SHORT]);
+    } else {
+       chip->duration[TPM_SHORT] = MICROSECS(chip->duration[TPM_SHORT]);
+    }
+
+        chip->duration[TPM_MEDIUM] =
MICROSECS(be32_to_cpu(duration_cap->tpm_medium));
+        chip->duration[TPM_LONG] =
MICROSECS(be32_to_cpu(duration_cap->tpm_long));
+}
+
+
+
+void tpm_continue_selftest(struct tpm_chip* chip) {
+   uint8_t data[] = {
+      0, 193,                 /* TPM_TAG_RQU_COMMAND */
+      0, 0, 0, 10,            /* length */
+      0, 0, 0, 83,            /* TPM_ORD_GetCapability */
+   };
+
+   tpm_transmit(chip, data, sizeof(data));
+}
+
+ssize_t tpm_getcap(struct tpm_chip *chip, uint32_t subcap_id, cap_t *cap,
+                   const char *desc)
+{
+        struct tpm_cmd_t tpm_cmd;
+        int rc;
+
+        tpm_cmd.header.in = tpm_getcap_header;
+        if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
+                tpm_cmd.params.getcap_in.cap = subcap_id;
+                /*subcap field not necessary */
+                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
+                tpm_cmd.header.in.length -= cpu_to_be32(sizeof(uint32_t));
+        } else {
+                if (subcap_id == TPM_CAP_FLAG_PERM ||
+                    subcap_id == TPM_CAP_FLAG_VOL)
+                        tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
+                else
+                        tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+                tpm_cmd.params.getcap_in.subcap = subcap_id;
+        }
+        rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+        if (!rc)
+                *cap = tpm_cmd.params.getcap_out.cap;
+        return rc;
+}
+
+
+struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
unsigned int irq)
+{
+   int i;
+   unsigned long addr;
+   struct tpm_chip* tpm = NULL;
+   uint32_t didvid;
+   uint32_t intfcaps;
+   uint32_t intmask;
+
+   printk("============= Init TPM TIS Driver ==============\n");
+
+   /*Sanity check the localities input */
+   if(localities & ~TPM_TIS_EN_LOCLALL) {
+      printk("init_tpm_tis() Invalid locality specification! %X\n",
localities);
+      goto abort_egress;
+   }
+
+   printk("IOMEM Machine Base Address: %lX\n", baseaddr);
+
+   /* Create the tpm data structure */
+   tpm = malloc(sizeof(struct tpm_chip));
+   __init_tpm_chip(tpm);
+
+   /* Set the enabled localities - if 0 we leave default as all enabled */
+   if(localities != 0) {
+      tpm->enabled_localities = localities;
+   }
+   printk("Enabled Localities: ");
+   for(i = 0; i < 5; ++i) {
+      if(locality_enabled(tpm, i)) {
+     printk("%d ", i);
+      }
+   }
+   printk("\n");
+
+   /* Set the base machine address */
+   tpm->baseaddr = baseaddr;
+
+   /* Set default timeouts */
+   tpm->timeout_a = MILLISECS(TIS_SHORT_TIMEOUT);
+   tpm->timeout_b = MILLISECS(TIS_LONG_TIMEOUT);
+   tpm->timeout_c = MILLISECS(TIS_SHORT_TIMEOUT);
+   tpm->timeout_d = MILLISECS(TIS_SHORT_TIMEOUT);
+
+   /*Map the mmio pages */
+   addr = tpm->baseaddr;
+   for(i = 0; i < 5; ++i) {
+      if(locality_enabled(tpm, i)) {
+     /* Map the page in now */
+     if((tpm->pages[i] = ioremap_nocache(addr, PAGE_SIZE)) == NULL) {
+        printk("Unable to map iomem page a address %p\n", addr);
+        goto abort_egress;
+     }
+
+     /* Set default locality to the first enabled one */
+     if (tpm->locality < 0) {
+        if(tpm_tis_request_locality(tpm, i) < 0) {
+           printk("Unable to request locality %d??\n", i);
+           goto abort_egress;
+        }
+     }
+      }
+      addr += PAGE_SIZE;
+   }
+
+
+   /* Get the vendor and device ids */
+   didvid = ioread32(TPM_DID_VID(tpm, tpm->locality));
+   tpm->did = didvid >> 16;
+   tpm->vid = didvid & 0xFFFF;
+
+
+   /* Get the revision id */
+   tpm->rid = ioread8(TPM_RID(tpm, tpm->locality));
+
+   printk("1.2 TPM (device-id=0x%X vendor-id = %X rev-id = %X)\n",
tpm->did, tpm->vid, tpm->rid);
+
+   intfcaps = ioread32(TPM_INTF_CAPS(tpm, tpm->locality));
+   printk("TPM interface capabilities (0x%x):\n", intfcaps);
+   if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
+      printk("\tBurst Count Static\n");
+   if (intfcaps & TPM_INTF_CMD_READY_INT)
+      printk("\tCommand Ready Int Support\n");
+   if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
+      printk("\tInterrupt Edge Falling\n");
+   if (intfcaps & TPM_INTF_INT_EDGE_RISING)
+      printk("\tInterrupt Edge Rising\n");
+   if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
+      printk("\tInterrupt Level Low\n");
+   if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
+      printk("\tInterrupt Level High\n");
+   if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
+      printk("\tLocality Change Int Support\n");
+   if (intfcaps & TPM_INTF_STS_VALID_INT)
+      printk("\tSts Valid Int Support\n");
+   if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
+      printk("\tData Avail Int Support\n");
+
+   /*Interupt setup */
+   intmask = ioread32(TPM_INT_ENABLE(tpm, tpm->locality));
+
+   intmask |= TPM_INTF_CMD_READY_INT
+      | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
+      | TPM_INTF_STS_VALID_INT;
+
+   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask);
+
+   /*If interupts are enabled, handle it */
+   if(irq) {
+      if(irq != TPM_PROBE_IRQ) {
+     tpm->irq = irq;
+      } else {
+     /*FIXME add irq probing feature later */
+     printk("IRQ probing not implemented\n");
+      }
+   }
+
+   if(tpm->irq) {
+      iowrite8(TPM_INT_VECTOR(tpm, tpm->locality), tpm->irq);
+
+      if(bind_pirq(tpm->irq, 1, tpm_tis_irq_handler, tpm) != 0) {
+     printk("Unabled to request irq: %u for use\n", tpm->irq);
+     printk("Will use polling mode\n");
+     tpm->irq = 0;
+      } else {
+     /* Clear all existing */
+     iowrite32(TPM_INT_STATUS(tpm, tpm->locality),
ioread32(TPM_INT_STATUS(tpm, tpm->locality)));
+
+     /* Turn on interrupts */
+     iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask |
TPM_GLOBAL_INT_ENABLE);
+      }
+   }
+
+   tpm_get_timeouts(tpm);
+   tpm_continue_selftest(tpm);
+
+
+   return tpm;
+abort_egress:
+   if(tpm != NULL) {
+      shutdown_tpm_tis(tpm);
+   }
+   return NULL;
+}
+
+void shutdown_tpm_tis(struct tpm_chip* tpm){
+   int i;
+
+   printk("Shutting down tpm_tis device\n");
+
+   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), ~TPM_GLOBAL_INT_ENABLE);
+
+   /*Unmap all of the mmio pages */
+   for(i = 0; i < 5; ++i) {
+      if(tpm->pages[i] != NULL) {
+     iounmap(tpm->pages[i], PAGE_SIZE);
+     tpm->pages[i] = NULL;
+      }
+   }
+   free(tpm);
+   return;
+}
+
+
+int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen)
+{
+   if(tpm->locality < 0) {
+      printk("tpm_tis_cmd() failed! locality not set!\n");
+      return -1;
+   }
+   if(reqlen > TPM_BUFSIZE) {
+      reqlen = TPM_BUFSIZE;
+   }
+   memcpy(tpm->data_buffer, req, reqlen);
+   *resplen = tpm_transmit(tpm, tpm->data_buffer, TPM_BUFSIZE);
+
+   *resp = malloc(*resplen);
+   memcpy(*resp, tpm->data_buffer, *resplen);
+   return 0;
+}
+
+#ifdef HAVE_LIBC
+int tpm_tis_open(struct tpm_chip* tpm)
+{
+   /* Silently prevent multiple opens */
+   if(tpm->fd != -1) {
+      return tpm->fd;
+   }
+
+   tpm->fd = alloc_fd(FTYPE_TPM_TIS);
+   printk("tpm_tis_open() -> %d\n", tpm->fd);
+   files[tpm->fd].tpm_tis.dev = tpm;
+   files[tpm->fd].tpm_tis.offset = 0;
+   files[tpm->fd].tpm_tis.respgot = 0;
+   return tpm->fd;
+}
+
+int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count)
+{
+   struct tpm_chip* tpm;
+   tpm = files[fd].tpm_tis.dev;
+
+   if(tpm->locality < 0) {
+      printk("tpm_tis_posix_write() failed! locality not set!\n");
+      errno = EINPROGRESS;
+      return -1;
+   }
+   if(count == 0) {
+      return 0;
+   }
+
+   /* Return an error if we are already processing a command */
+   if(count > TPM_BUFSIZE) {
+      count = TPM_BUFSIZE;
+   }
+   /* Send the command now */
+   memcpy(tpm->data_buffer, buf, count);
+   if((tpm->data_len = tpm_transmit(tpm, tpm->data_buffer,
TPM_BUFSIZE)) < 0) {
+      errno = EIO;
+      return -1;
+   }
+   return count;
+}
+
+int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count)
+{
+   int rc;
+   struct tpm_chip* tpm;
+   tpm = files[fd].tpm_tis.dev;
+
+   if(count == 0) {
+      return 0;
+   }
+
+   /* If there is no tpm resp to read, return EIO */
+   if(tpm->data_len < 0) {
+      errno = EIO;
+      return -1;
+   }
+
+
+   /* Handle EOF case */
+   if(files[fd].tpm_tis.offset >= tpm->data_len) {
+      rc = 0;
+   } else {
+      rc = min(tpm->data_len - files[fd].tpm_tis.offset, count);
+      memcpy(buf, tpm->data_buffer + files[fd].tpm_tis.offset, rc);
+   }
+   files[fd].tpm_tis.offset += rc;
+   /* Reset the data pending flag */
+   return rc;
+}
+int tpm_tis_posix_fstat(int fd, struct stat* buf)
+{
+   struct tpm_chip* tpm;
+   tpm = files[fd].tpm_tis.dev;
+
+   buf->st_mode = O_RDWR;
+   buf->st_uid = 0;
+   buf->st_gid = 0;
+   buf->st_size = be32_to_cpu(*((uint32_t*)(tpm->data_buffer + 2)));
+   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
+   return 0;
+}
+
+
+#endif
diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c
--- /dev/null
+++ b/extras/mini-os/tpmback.c
@@ -0,0 +1,1114 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This driver 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based upon the files:
+ *  drivers/xen/tpmbk.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <mini-os/os.h>
+#include <mini-os/xenbus.h>
+#include <mini-os/events.h>
+#include <errno.h>
+#include <mini-os/gnttab.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/tpmif.h>
+#include <xen/io/protocols.h>
+#include <mini-os/xmalloc.h>
+#include <time.h>
+#include <mini-os/tpmback.h>
+#include <mini-os/lib.h>
+#include <fcntl.h>
+#include <mini-os/mm.h>
+#include <mini-os/posix/sys/mman.h>
+#include <mini-os/semaphore.h>
+#include <mini-os/wait.h>
+
+
+#ifndef HAVE_LIBC
+#define strtoul simple_strtoul
+#endif
+
+//#define TPMBACK_PRINT_DEBUG
+#ifdef TPMBACK_PRINT_DEBUG
+#define TPMBACK_DEBUG(fmt,...) printk("Tpmback:Debug("__FILE__":%d) "
fmt, __LINE__, ##__VA_ARGS__)
+#define TPMBACK_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
+#else
+#define TPMBACK_DEBUG(fmt,...)
+#endif
+#define TPMBACK_ERR(fmt,...) printk("Tpmback:Error " fmt, ##__VA_ARGS__)
+#define TPMBACK_LOG(fmt,...) printk("Tpmback:Info " fmt, ##__VA_ARGS__)
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+/* Default size of the tpmif array at initialization */
+#define DEF_ARRAY_SIZE 1
+
+/* tpmif and tpmdev flags */
+#define TPMIF_CLOSED 1
+#define TPMIF_REQ_READY 2
+
+struct tpmif {
+   domid_t domid;
+   unsigned int handle;
+
+   char* fe_path;
+   char* fe_state_path;
+
+   /* Locally bound event channel*/
+   evtchn_port_t evtchn;
+
+   /* Shared page */
+   tpmif_tx_interface_t* tx;
+
+   /* pointer to TPMIF_RX_RING_SIZE pages */
+   void** pages;
+
+   enum xenbus_state state;
+   enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
+
+   char* uuid;
+
+   /* state flags */
+   int flags;
+};
+typedef struct tpmif tpmif_t;
+
+struct tpmback_dev {
+
+   tpmif_t** tpmlist;
+   unsigned long num_tpms;
+   unsigned long num_alloc;
+
+   struct gntmap map;
+
+   /* True if at least one tpmif has a request to be handled */
+   int flags;
+
+   /* exclusive domains, see init_tpmback comment in tpmback.h */
+   char** exclusive_uuids;
+
+   xenbus_event_queue events;
+
+   /* Callbacks */
+   void (*open_callback)(domid_t, unsigned int);
+   void (*close_callback)(domid_t, unsigned int);
+   void (*suspend_callback)(domid_t, unsigned int);
+   void (*resume_callback)(domid_t, unsigned int);
+};
+typedef struct tpmback_dev tpmback_dev_t;
+
+enum { EV_NONE, EV_NEWFE, EV_STCHNG } tpm_ev_enum;
+
+/* Global objects */
+static struct thread* eventthread = NULL;
+static tpmback_dev_t gtpmdev = {
+   .tpmlist = NULL,
+   .num_tpms = 0,
+   .num_alloc = 0,
+   .flags = TPMIF_CLOSED,
+   .events = NULL,
+   .open_callback = NULL,
+   .close_callback = NULL,
+   .suspend_callback = NULL,
+   .resume_callback = NULL,
+};
+struct wait_queue_head waitq;
+int globalinit = 0;
+
+/************************************
+ * TPMIF SORTED ARRAY FUNCTIONS
+ * tpmback_dev_t.tpmlist is a sorted array, sorted by domid and then
handle number
+ * Duplicates are not allowed
+ * **********************************/
+
+inline void tpmif_req_ready(tpmif_t* tpmif) {
+   tpmif->flags |= TPMIF_REQ_READY;
+   gtpmdev.flags |= TPMIF_REQ_READY;
+}
+
+inline void tpmdev_check_req(void) {
+   int i;
+   int flags;
+   local_irq_save(flags);
+   for(i = 0; i < gtpmdev.num_tpms; ++i) {
+      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
+     gtpmdev.flags |= TPMIF_REQ_READY;
+     local_irq_restore(flags);
+     return;
+      }
+   }
+   gtpmdev.flags &= ~TPMIF_REQ_READY;
+   local_irq_restore(flags);
+}
+
+inline void tpmif_req_finished(tpmif_t* tpmif) {
+   tpmif->flags &= ~TPMIF_REQ_READY;
+   tpmdev_check_req();
+}
+
+int __get_tpmif_index(int st, int n, domid_t domid, unsigned int handle)
+{
+   int i = st + n /2;
+   tpmif_t* tmp;
+
+   if( n <= 0 )
+      return -1;
+
+   tmp = gtpmdev.tpmlist[i];
+   if(domid == tmp->domid && tmp->handle == handle) {
+      return i;
+   } else if ( (domid < tmp->domid) ||
+     (domid == tmp->domid && handle < tmp->handle)) {
+      return __get_tpmif_index(st, n/2, domid, handle);
+   } else {
+      return __get_tpmif_index(i + 1, n/2 - ((n +1) % 2), domid, handle);
+   }
+}
+
+/* Returns the array index of the tpmif domid/handle. Returns -1 if no
such tpmif exists */
+int get_tpmif_index(domid_t domid, unsigned int handle)
+{
+   int flags;
+   int index;
+   local_irq_save(flags);
+   index = __get_tpmif_index(0, gtpmdev.num_tpms, domid, handle);
+   local_irq_restore(flags);
+   return index;
+}
+
+/* Returns the tpmif domid/handle or NULL if none exists */
+tpmif_t* get_tpmif(domid_t domid, unsigned int handle)
+{
+   int flags;
+   int i;
+   tpmif_t* ret;
+   local_irq_save(flags);
+   i = get_tpmif_index(domid, handle);
+   if (i < 0) {
+      ret = NULL;
+   } else {
+      ret = gtpmdev.tpmlist[i];
+   }
+   local_irq_restore(flags);
+   return ret;
+}
+
+/* Remove the given tpmif. Returns 0 if it was removed, -1 if it was
not removed */
+int remove_tpmif(tpmif_t* tpmif)
+{
+   int i, j;
+   char* err;
+   int flags;
+   local_irq_save(flags);
+
+   /* Find the index in the array if it exists */
+   i = get_tpmif_index(tpmif->domid, tpmif->handle);
+   if (i < 0) {
+      goto error;
+   }
+
+   /* Remove the interface from the list */
+   for(j = i; j < gtpmdev.num_tpms - 1; ++j) {
+      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j+1];
+   }
+   gtpmdev.tpmlist[j] = NULL;
+   --gtpmdev.num_tpms;
+
+   /* If removed tpm was the only ready tpm, then we need to check and
turn off the ready flag */
+   tpmdev_check_req();
+
+   local_irq_restore(flags);
+
+   /* Stop listening for events on this tpm interface */
+   if((err = xenbus_unwatch_path_token(XBT_NIL, tpmif->fe_state_path,
tpmif->fe_state_path))) {
+      TPMBACK_ERR("Unable to unwatch path token `%s' Error was %s
Ignoring..\n", tpmif->fe_state_path, err);
+      free(err);
+   }
+
+   return 0;
+error:
+   local_irq_restore(flags);
+   return -1;
+}
+
+/* Insert tpmif into dev->tpmlist. Returns 0 on success and non zero on
error.
+ * It is an error to insert a tpmif with the same domid and handle
+ * number
+ * as something already in the list */
+int insert_tpmif(tpmif_t* tpmif)
+{
+   int flags;
+   unsigned int i, j;
+   tpmif_t* tmp;
+   char* err;
+
+   local_irq_save(flags);
+
+   /*Check if we need to allocate more space */
+   if (gtpmdev.num_tpms == gtpmdev.num_alloc) {
+      gtpmdev.num_alloc *= 2;
+      gtpmdev.tpmlist = realloc(gtpmdev.tpmlist, gtpmdev.num_alloc);
+   }
+
+   /*Find where to put the new interface */
+   for(i = 0; i < gtpmdev.num_tpms; ++i)
+   {
+      tmp = gtpmdev.tpmlist[i];
+      if(tpmif->domid == tmp->domid && tpmif->handle == tmp->handle) {
+     TPMBACK_ERR("Tried to insert duplicate tpm interface %u/%u\n",
(unsigned int) tpmif->domid, tpmif->handle);
+     goto error;
+      }
+      if((tpmif->domid < tmp->domid) ||
+        (tpmif->domid == tmp->domid && tpmif->handle < tmp->handle)) {
+     break;
+      }
+   }
+
+   /*Shift all the tpm pointers past i down one */
+   for(j = gtpmdev.num_tpms; j > i; --j) {
+      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j-1];
+   }
+
+   /*Add the new interface */
+   gtpmdev.tpmlist[i] = tpmif;
+   ++gtpmdev.num_tpms;
+
+   /*Should not be needed, anything inserted with ready flag is
probably an error */
+   tpmdev_check_req();
+
+   local_irq_restore(flags);
+
+   /*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)))
+   {
+      /* if we got an error here we should carefully remove the
interface and then return */
+      TPMBACK_ERR("Unable to watch path token `%s' Error was %s\n",
tpmif->fe_state_path, err);
+      free(err);
+      remove_tpmif(tpmif);
+      goto error_post_irq;
+   }
+
+   return 0;
+error:
+   local_irq_restore(flags);
+error_post_irq:
+   return -1;
+}
+
+
+/*****************
+ * CHANGE BACKEND STATE
+ * *****************/
+/*Attempts to change the backend state in xenstore
+ * returns 0 on success and non-zero on error */
+int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state)
+{
+   char path[512];
+   char *value;
+   char *err;
+   enum xenbus_state readst;
+   TPMBACK_DEBUG("Backend state change %u/%u from=%d to=%d\n",
(unsigned int) tpmif->domid, tpmif->handle, tpmif->state, state);
+   if (tpmif->state == state)
+      return 0;
+
+   snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int)
tpmif->domid, tpmif->handle);
+
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMBACK_ERR("Unable to read backend state %s, error was %s\n",
path, err);
+      free(err);
+      return -1;
+   }
+   if(sscanf(value, "%d", &readst) != 1) {
+      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
+      free(value);
+      return -1;
+   }
+   free(value);
+
+   /* It's possible that the backend state got updated by hotplug or
something else behind our back */
+   if(readst != tpmif->state) {
+      TPMBACK_DEBUG("tpm interface state was %d but xenstore state was
%d!\n", tpmif->state, readst);
+      tpmif->state = readst;
+   }
+
+   /*If if the state isnt changing, then we dont update xenstore b/c we
dont want to fire extraneous events */
+   if(tpmif->state == state) {
+      return 0;
+   }
+
+   /*update xenstore*/
+   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
tpmif->domid, tpmif->handle);
+   if((err = xenbus_printf(XBT_NIL, path, "state", "%u", state))) {
+      TPMBACK_ERR("Error writing to xenstore %s, error was %s new
state=%d\n", path, err, state);
+      free(err);
+      return -1;
+   }
+
+   tpmif->state = state;
+
+   return 0;
+}
+/**********************************
+ * TPMIF CREATION AND DELETION
+ * *******************************/
+inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   tpmif = malloc(sizeof(*tpmif));
+   tpmif->domid = domid;
+   tpmif->handle = handle;
+   tpmif->fe_path = NULL;
+   tpmif->fe_state_path = NULL;
+   tpmif->state = XenbusStateInitialising;
+   tpmif->status = DISCONNECTED;
+   tpmif->tx = NULL;
+   tpmif->pages = NULL;
+   tpmif->flags = 0;
+   tpmif->uuid = NULL;
+   return tpmif;
+}
+
+void __free_tpmif(tpmif_t* tpmif)
+{
+   if(tpmif->pages) {
+      free(tpmif->pages);
+   }
+   if(tpmif->fe_path) {
+      free(tpmif->fe_path);
+   }
+   if(tpmif->fe_state_path) {
+      free(tpmif->fe_state_path);
+   }
+   if(tpmif->uuid) {
+      free(tpmif->uuid);
+   }
+   free(tpmif);
+}
+/* Creates a new tpm interface, adds it to the sorted array and returns it.
+ * returns NULL on error
+ * If the tpm interface already exists, it is returned*/
+tpmif_t* new_tpmif(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   char* err;
+   char path[512];
+
+   /* Make sure we haven't already created this tpm
+    * Double events can occur */
+   if((tpmif = get_tpmif(domid, handle)) != NULL) {
+      return tpmif;
+   }
+
+   tpmif = __init_tpmif(domid, handle);
+
+   /* Get the uuid from xenstore */
+   snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domid,
handle);
+   if((err = xenbus_read(XBT_NIL, path, &tpmif->uuid))) {
+      TPMBACK_ERR("Error reading %s, Error = %s\n", path, err);
+      free(err);
+      goto error;
+   }
+
+   /* Do the exclusive uuid check now */
+   if(gtpmdev.exclusive_uuids != NULL) {
+      char** ptr;
+
+      /* Check that its in the whitelist */
+      for(ptr = gtpmdev.exclusive_uuids; *ptr != NULL; ++ptr) {
+     if(!strcmp(tpmif->uuid, *ptr)) {
+        break;
+     }
+      }
+      /* If *ptr == NULL then we went through the whole list without a
match, so close the connection */
+      if(*ptr == NULL) {
+     tpmif_change_state(tpmif, XenbusStateClosed);
+     TPMBACK_ERR("Frontend %u/%u tried to connect with invalid
uuid=%s\n", (unsigned int) domid, handle, tpmif->uuid);
+     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;
+   }
+
+   snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int)
domid, handle);
+   if((err = xenbus_read(XBT_NIL, path, &tpmif->fe_path))) {
+      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s),
Error = %s", path, err);
+      free(err);
+      goto error;
+   }
+
+   /*Set the state path */
+   tpmif->fe_state_path = malloc(strlen(tpmif->fe_path) + 7);
+   strcpy(tpmif->fe_state_path, tpmif->fe_path);
+   strcat(tpmif->fe_state_path, "/state");
+
+   if(insert_tpmif(tpmif)) {
+      goto error;
+   }
+   TPMBACK_DEBUG("New tpmif %u/%u\n", (unsigned int) tpmif->domid,
tpmif->handle);
+   /* Do the callback now */
+   if(gtpmdev.open_callback) {
+      gtpmdev.open_callback(tpmif->domid, tpmif->handle);
+   }
+   return tpmif;
+error:
+   __free_tpmif(tpmif);
+   return NULL;
+
+}
+
+/* Removes tpmif from dev->tpmlist and frees it's memory usage */
+void free_tpmif(tpmif_t* tpmif)
+{
+   char* err;
+   char path[512];
+   TPMBACK_DEBUG("Free tpmif %u/%u\n", (unsigned int) tpmif->domid,
tpmif->handle);
+   if(tpmif->flags & TPMIF_CLOSED) {
+      TPMBACK_ERR("Tried to free an instance twice! Theres a bug
somewhere!\n");
+      BUG();
+   }
+   tpmif->flags = TPMIF_CLOSED;
+
+   tpmif_change_state(tpmif, XenbusStateClosing);
+
+   /* Unmap share page and unbind event channel */
+   if(tpmif->status == CONNECTED) {
+      tpmif->status = DISCONNECTING;
+      mask_evtchn(tpmif->evtchn);
+
+      if(gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1)) {
+     TPMBACK_ERR("%u/%u Error occured while trying to unmap shared
page\n", (unsigned int) tpmif->domid, tpmif->handle);
+      }
+
+      unbind_evtchn(tpmif->evtchn);
+   }
+   tpmif->status = DISCONNECTED;
+   tpmif_change_state(tpmif, XenbusStateClosed);
+
+   /* Do the callback now */
+   if(gtpmdev.close_callback) {
+      gtpmdev.close_callback(tpmif->domid, tpmif->handle);
+   }
+
+   /* remove from array */
+   remove_tpmif(tpmif);
+
+   /* Wake up anyone possibly waiting on this interface and let them
exit */
+   wake_up(&waitq);
+   schedule();
+
+   /* Remove the old xenbus entries */
+   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
tpmif->domid, tpmif->handle);
+   if((err = xenbus_rm(XBT_NIL, path))) {
+      TPMBACK_ERR("Error cleaning up xenbus entries path=%s
error=%s\n", path, err);
+      free(err);
+   }
+
+   TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int)
tpmif->domid, tpmif->handle);
+
+   /* free memory */
+   __free_tpmif(tpmif);
+
+}
+
+/**********************
+ * REMAINING TPMBACK FUNCTIONS
+ * ********************/
+
+/*Event channel handler */
+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);
+
+}
+
+/* Connect to frontend */
+int connect_fe(tpmif_t* tpmif)
+{
+   char path[512];
+   char* err, *value;
+   uint32_t domid;
+   grant_ref_t ringref;
+   evtchn_port_t evtchn;
+
+   /* If already connected then quit */
+   if (tpmif->status == CONNECTED) {
+      TPMBACK_DEBUG("%u/%u tried to connect while it was already
connected?\n", (unsigned int) tpmif->domid, tpmif->handle);
+      return 0;
+   }
+
+   /* Fetch the grant reference */
+   snprintf(path, 512, "%s/ring-ref", tpmif->fe_path);
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
Error = %s", path, err);
+      free(err);
+      return -1;
+   }
+   if(sscanf(value, "%d", &ringref) != 1) {
+      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
+      free(value);
+      return -1;
+   }
+   free(value);
+
+
+   /* Fetch the event channel*/
+   snprintf(path, 512, "%s/event-channel", tpmif->fe_path);
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
Error = %s", path, err);
+      free(err);
+      return -1;
+   }
+   if(sscanf(value, "%d", &evtchn) != 1) {
+      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
+      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) {
+      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)))
+   {
+      TPMBACK_ERR("%u/%u Unable to bind to interdomain event
channel!\n", (unsigned int) tpmif->domid, tpmif->handle);
+      goto error_post_map;
+   }
+   unmask_evtchn(tpmif->evtchn);
+
+   /* Write the ready flag and change status to connected */
+   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
tpmif->domid, tpmif->handle);
+   if((err = xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) {
+      TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n",
(unsigned int) tpmif->domid, tpmif->handle);
+      free(err);
+      goto error_post_evtchn;
+   }
+   tpmif->status = CONNECTED;
+   if((tpmif_change_state(tpmif, XenbusStateConnected))){
+      goto error_post_evtchn;
+   }
+
+   TPMBACK_LOG("Frontend %u/%u connected\n", (unsigned int)
tpmif->domid, tpmif->handle);
+
+   return 0;
+error_post_evtchn:
+   mask_evtchn(tpmif->evtchn);
+   unbind_evtchn(tpmif->evtchn);
+error_post_map:
+   gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1);
+   return -1;
+}
+
+static int frontend_changed(tpmif_t* tpmif)
+{
+   int state = xenbus_read_integer(tpmif->fe_state_path);
+   if(state < 0) {
+      state = XenbusStateUnknown;
+   }
+
+   TPMBACK_DEBUG("Frontend %u/%u state changed to %d\n", (unsigned int)
tpmif->domid, tpmif->handle, state);
+
+   switch (state) {
+      case XenbusStateInitialising:
+      case XenbusStateInitialised:
+     break;
+
+      case XenbusStateConnected:
+     if(connect_fe(tpmif)) {
+        TPMBACK_ERR("Failed to connect to front end %u/%u\n", (unsigned
int) tpmif->domid, tpmif->handle);
+        tpmif_change_state(tpmif, XenbusStateClosed);
+        return -1;
+     }
+     break;
+
+      case XenbusStateClosing:
+     tpmif_change_state(tpmif, XenbusStateClosing);
+     break;
+
+      case XenbusStateUnknown: /* keep it here */
+      case XenbusStateClosed:
+     free_tpmif(tpmif);
+     break;
+
+      default:
+     TPMBACK_DEBUG("BAD STATE CHANGE %u/%u state = %d for tpmif\n",
(unsigned int) tpmif->domid, tpmif->handle, state);
+     return -1;
+   }
+   return 0;
+}
+
+
+/* parses the string that comes out of xenbus_watch_wait_return. */
+static int parse_eventstr(const char* evstr, domid_t* domid, unsigned
int* handle)
+{
+   int ret;
+   char cmd[40];
+   char* err;
+   char* value;
+   unsigned int udomid = 0;
+   tpmif_t* tpmif;
+   /* First check for new frontends, this occurs when
/backend/vtpm/<domid>/<handle> gets created. Note we what the sscanf to
fail on the last %s */
+   if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd)
== 2) {
+      *domid = udomid;
+      /* Make sure the entry exists, if this event triggers because the
entry dissapeared then ignore it */
+      if((err = xenbus_read(XBT_NIL, evstr, &value))) {
+     free(err);
+     return EV_NONE;
+      }
+      free(value);
+      /* Make sure the tpmif entry does not already exist, this should
not happen */
+      if((tpmif = get_tpmif(*domid, *handle)) != NULL) {
+     TPMBACK_DEBUG("Duplicate tpm entries! %u %u\n", tpmif->domid,
tpmif->handle);
+     return EV_NONE;
+      }
+      return EV_NEWFE;
+   } else if((ret = sscanf(evstr,
"/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) == 3) {
+      *domid = udomid;
+      if (!strcmp(cmd, "state"))
+     return EV_STCHNG;
+   }
+   return EV_NONE;
+}
+
+void handle_backend_event(char* evstr) {
+   tpmif_t* tpmif;
+   domid_t domid;
+   unsigned int handle;
+   int event;
+
+   TPMBACK_DEBUG("Xenbus Event: %s\n", evstr);
+
+   event = parse_eventstr(evstr, &domid, &handle);
+
+   switch(event) {
+      case EV_NEWFE:
+     if(new_tpmif(domid, handle) == NULL) {
+        TPMBACK_ERR("Failed to create new tpm instance %u/%u\n",
(unsigned int) domid, handle);
+     }
+     wake_up(&waitq);
+     break;
+      case EV_STCHNG:
+     if((tpmif = get_tpmif(domid, handle))) {
+        frontend_changed(tpmif);
+     } else {
+        TPMBACK_DEBUG("Event Received for non-existant tpm!
instance=%u/%u xenbus_event=%s\n", (unsigned int) domid, handle, evstr);
+     }
+     break;
+   }
+}
+
+/* Runs through the given path and creates events recursively
+ * for all of its children.
+ * @path - xenstore path to scan */
+static void generate_backend_events(const char* path)
+{
+   char* err;
+   int i, len;
+   char **dirs;
+   char *entry;
+
+   if((err = xenbus_ls(XBT_NIL, path, &dirs)) != NULL) {
+      free(err);
+      return;
+   }
+
+   for(i = 0; dirs[i] != NULL; ++i) {
+      len = strlen(path) + strlen(dirs[i]) + 2;
+      entry = malloc(len);
+      snprintf(entry, len, "%s/%s", path, dirs[i]);
+
+      /* Generate and handle event for the entry itself */
+      handle_backend_event(entry);
+
+      /* Do children */
+      generate_backend_events(entry);
+
+      /* Cleanup */
+      free(entry);
+      free(dirs[i]);
+   }
+   free(dirs);
+   return;
+}
+
+char* tpmback_get_uuid(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   if((tpmif = get_tpmif(domid, handle)) == NULL) {
+      TPMBACK_DEBUG("get_uuid() failed, %u/%u is an invalid
frontend\n", (unsigned int) domid, handle);
+      return NULL;
+   }
+
+   return tpmif->uuid;
+}
+
+void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.open_callback = cb;
+}
+void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.close_callback = cb;
+}
+void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.suspend_callback = cb;
+}
+void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.resume_callback = cb;
+}
+
+static void event_listener(void)
+{
+   const char* bepath = "backend/vtpm";
+   char **path;
+   char* err;
+
+   /* Setup the backend device watch */
+   if((err = xenbus_watch_path_token(XBT_NIL, bepath, bepath,
&gtpmdev.events)) != NULL) {
+      TPMBACK_ERR("xenbus_watch_path_token(%s) failed with error
%s!\n", bepath, err);
+      free(err);
+      goto egress;
+   }
+
+   /* Check for any frontends that connected before we set the watch.
+    * This is almost guaranteed to happen if both domains are started
+    * immediatly one after the other.
+    * We do this by manually generating events on everything in the backend
+    * path */
+   generate_backend_events(bepath);
+
+   /* Wait and listen for changes in frontend connections */
+   while(1) {
+      path = xenbus_wait_for_watch_return(&gtpmdev.events);
+
+      /*If quit flag was set then exit */
+      if(gtpmdev.flags & TPMIF_CLOSED) {
+     TPMBACK_DEBUG("listener thread got quit event. Exiting..\n");
+     free(path);
+     break;
+      }
+      handle_backend_event(*path);
+      free(path);
+
+   }
+
+   if((err = xenbus_unwatch_path_token(XBT_NIL, bepath, bepath)) != NULL) {
+      free(err);
+   }
+egress:
+   return;
+}
+
+void event_thread(void* p) {
+   event_listener();
+}
+
+void init_tpmback(char** exclusive_uuids)
+{
+   if(!globalinit) {
+      init_waitqueue_head(&waitq);
+      globalinit = 1;
+   }
+   printk("============= Init TPM BACK ================\n");
+   gtpmdev.tpmlist = malloc(sizeof(tpmif_t*) * DEF_ARRAY_SIZE);
+   gtpmdev.num_alloc = DEF_ARRAY_SIZE;
+   gtpmdev.num_tpms = 0;
+   gtpmdev.flags = 0;
+   gtpmdev.exclusive_uuids = exclusive_uuids;
+
+   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
+   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
+
+   eventthread = create_thread("tpmback-listener", event_thread, NULL);
+
+}
+
+void shutdown_tpmback(void)
+{
+   /* Disable callbacks */
+   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
+   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
+
+   TPMBACK_LOG("Shutting down tpm backend\n");
+   /* Set the quit flag */
+   gtpmdev.flags = TPMIF_CLOSED;
+
+   //printk("num tpms is %d\n", gtpmdev.num_tpms);
+   /*Free all backend instances */
+   while(gtpmdev.num_tpms) {
+      free_tpmif(gtpmdev.tpmlist[0]);
+   }
+   free(gtpmdev.tpmlist);
+   gtpmdev.tpmlist = NULL;
+   gtpmdev.num_alloc = 0;
+
+   /* Wake up anyone possibly waiting on the device and let them exit */
+   wake_up(&waitq);
+   schedule();
+}
+
+inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int
handle, char* uuid)
+{
+   tpmcmd->domid = domid;
+   tpmcmd->handle = handle;
+   tpmcmd->uuid = uuid;
+   tpmcmd->req = NULL;
+   tpmcmd->req_len = 0;
+   tpmcmd->resp = NULL;
+   tpmcmd->resp_len = 0;
+}
+
+tpmcmd_t* get_request(tpmif_t* tpmif) {
+   tpmcmd_t* cmd;
+   tpmif_tx_request_t* tx;
+   int offset;
+   int tocopy;
+   int i;
+   uint32_t domid;
+   int flags;
+
+   local_irq_save(flags);
+
+   /* Allocate the cmd object to hold the data */
+   if((cmd = malloc(sizeof(*cmd))) == NULL) {
+      goto error;
+   }
+   init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid);
+
+   tx = &tpmif->tx->ring[0].req;
+   cmd->req_len = tx->size;
+   /* 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);
+
+   }
+
+#ifdef TPMBACK_PRINT_DEBUG
+   TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u",
(unsigned int) tpmif->domid, tpmif->handle, cmd->req_len);
+   for(i = 0; i < cmd->req_len; ++i) {
+      if (!(i % 30)) {
+     TPMBACK_DEBUG_MORE("\n");
+      }
+      TPMBACK_DEBUG_MORE("%02hhX ", cmd->req[i]);
+   }
+   TPMBACK_DEBUG_MORE("\n\n");
+#endif
+
+   local_irq_restore(flags);
+   return cmd;
+error:
+   if(cmd != NULL) {
+      if (cmd->req != NULL) {
+     free(cmd->req);
+     cmd->req = NULL;
+      }
+      free(cmd);
+      cmd = NULL;
+   }
+   local_irq_restore(flags);
+   return NULL;
+
+}
+
+void send_response(tpmcmd_t* cmd, tpmif_t* tpmif)
+{
+   tpmif_tx_request_t* tx;
+   int offset;
+   int i;
+   uint32_t domid;
+   int tocopy;
+   int flags;
+
+   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);
+
+   }
+
+#ifdef TPMBACK_PRINT_DEBUG
+   TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int)
tpmif->domid, tpmif->handle, cmd->resp_len);
+   for(i = 0; i < cmd->resp_len; ++i) {
+      if (!(i % 30)) {
+     TPMBACK_DEBUG_MORE("\n");
+      }
+      TPMBACK_DEBUG_MORE("%02hhX ", cmd->resp[i]);
+   }
+   TPMBACK_DEBUG_MORE("\n\n");
+#endif
+   /* clear the ready flag and send the event channel notice to the
frontend */
+   tpmif_req_finished(tpmif);
+   notify_remote_via_evtchn(tpmif->evtchn);
+error:
+   local_irq_restore(flags);
+   return;
+}
+
+tpmcmd_t* tpmback_req_any(void)
+{
+   int i;
+   /* Block until something has a request */
+   wait_event(waitq, (gtpmdev.flags & (TPMIF_REQ_READY | TPMIF_CLOSED)));
+
+   /* Check if were shutting down */
+   if(gtpmdev.flags & TPMIF_CLOSED) {
+      /* if something was waiting for us to give up the queue so it can
shutdown, let it finish */
+      schedule();
+      return NULL;
+   }
+
+   for(i = 0; i < gtpmdev.num_tpms; ++i) {
+      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
+     return get_request(gtpmdev.tpmlist[i]);
+      }
+   }
+
+   TPMBACK_ERR("backend request ready flag was set but no interfaces
were actually ready\n");
+   return NULL;
+}
+
+tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   tpmif = get_tpmif(domid, handle);
+   if(tpmif == NULL) {
+      return NULL;
+   }
+
+   wait_event(waitq, (tpmif->flags & (TPMIF_REQ_READY | TPMIF_CLOSED)
|| gtpmdev.flags & TPMIF_CLOSED));
+
+   /* Check if were shutting down */
+   if(tpmif->flags & TPMIF_CLOSED || gtpmdev.flags & TPMIF_CLOSED) {
+      /* if something was waiting for us to give up the queue so it can
free this instance, let it finish */
+      schedule();
+      return NULL;
+   }
+
+   return get_request(tpmif);
+}
+
+void tpmback_resp(tpmcmd_t* tpmcmd)
+{
+   tpmif_t* tpmif;
+
+   /* Get the associated interface, if it doesnt exist then just quit */
+   tpmif = get_tpmif(tpmcmd->domid, tpmcmd->handle);
+   if(tpmif == NULL) {
+      TPMBACK_ERR("Tried to send a reponse to non existant frontend
%u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
+      goto end;
+   }
+
+   if(!(tpmif->flags & TPMIF_REQ_READY)) {
+      TPMBACK_ERR("Tried to send response to a frontend that was not
waiting for one %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
+      goto end;
+   }
+
+   /* Send response to frontend */
+   send_response(tpmcmd, tpmif);
+
+end:
+   if(tpmcmd->req != NULL) {
+      free(tpmcmd->req);
+   }
+   free(tpmcmd);
+   return;
+}
+
+int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int *handle)
+{
+   tpmif_t* tpmif;
+   int flags;
+   wait_event(waitq, ((gtpmdev.num_tpms > 0) || gtpmdev.flags &
TPMIF_CLOSED));
+   if(gtpmdev.flags & TPMIF_CLOSED) {
+      return -1;
+   }
+   local_irq_save(flags);
+   tpmif = gtpmdev.tpmlist[0];
+   *domid = tpmif->domid;
+   *handle = tpmif->handle;
+   local_irq_restore(flags);
+
+   return 0;
+}
+
+int tpmback_num_frontends(void)
+{
+   return gtpmdev.num_tpms;
+}
diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c
--- /dev/null
+++ b/extras/mini-os/tpmfront.c
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This driver 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_vtpm.c
+ *  drivers/char/tpm/tpm_xen.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <mini-os/os.h>
+#include <mini-os/xenbus.h>
+#include <mini-os/xmalloc.h>
+#include <mini-os/events.h>
+#include <mini-os/wait.h>
+#include <mini-os/gnttab.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/tpmif.h>
+#include <mini-os/tpmfront.h>
+#include <fcntl.h>
+
+//#define TPMFRONT_PRINT_DEBUG
+#ifdef TPMFRONT_PRINT_DEBUG
+#define TPMFRONT_DEBUG(fmt,...) printk("Tpmfront:Debug("__FILE__":%d) "
fmt, __LINE__, ##__VA_ARGS__)
+#define TPMFRONT_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
+#else
+#define TPMFRONT_DEBUG(fmt,...)
+#endif
+#define TPMFRONT_ERR(fmt,...) printk("Tpmfront:Error " fmt, ##__VA_ARGS__)
+#define TPMFRONT_LOG(fmt,...) printk("Tpmfront:Info " fmt, ##__VA_ARGS__)
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void
*data) {
+   struct tpmfront_dev* dev = (struct tpmfront_dev*) data;
+   /*If we get a response when we didnt make a request, just ignore it */
+   if(!dev->waiting) {
+      return;
+   }
+
+   dev->waiting = 0;
+#ifdef HAVE_LIBC
+   if(dev->fd >= 0) {
+      files[dev->fd].read = 1;
+   }
+#endif
+   wake_up(&dev->waitq);
+}
+
+static int publish_xenbus(struct tpmfront_dev* dev) {
+   xenbus_transaction_t xbt;
+   int retry;
+   char* err;
+   /* Write the grant reference and event channel to xenstore */
+again:
+   if((err = xenbus_transaction_start(&xbt))) {
+      TPMFRONT_ERR("Unable to start xenbus transaction, error was
%s\n", err);
+      free(err);
+      return -1;
+   }
+
+   if((err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
(unsigned int) dev->ring_ref))) {
+      TPMFRONT_ERR("Unable to write %s/ring-ref, error was %s\n",
dev->nodename, err);
+      free(err);
+      goto abort_transaction;
+   }
+
+   if((err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
(unsigned int) dev->evtchn))) {
+      TPMFRONT_ERR("Unable to write %s/event-channel, error was %s\n",
dev->nodename, err);
+      free(err);
+      goto abort_transaction;
+   }
+
+   if((err = xenbus_transaction_end(xbt, 0, &retry))) {
+      TPMFRONT_ERR("Unable to complete xenbus transaction, error was
%s\n", err);
+      free(err);
+      return -1;
+   }
+   if(retry) {
+      goto again;
+   }
+
+   return 0;
+abort_transaction:
+   if((err = xenbus_transaction_end(xbt, 1, &retry))) {
+      free(err);
+   }
+   return -1;
+}
+
+static int wait_for_backend_connect(xenbus_event_queue* events, char* path)
+{
+   int state;
+
+   TPMFRONT_LOG("Waiting for backend connection..\n");
+   /* Wait for the backend to connect */
+   while(1) {
+      state = xenbus_read_integer(path);
+      if ( state < 0)
+     state = XenbusStateUnknown;
+      switch(state) {
+     /* Bad states, we quit with error */
+     case XenbusStateUnknown:
+     case XenbusStateClosing:
+     case XenbusStateClosed:
+        TPMFRONT_ERR("Unable to connect to backend\n");
+        return -1;
+     /* If backend is connected then break out of loop */
+     case XenbusStateConnected:
+        TPMFRONT_LOG("Backend Connected\n");
+        return 0;
+     default:
+        xenbus_wait_for_watch(events);
+      }
+   }
+
+}
+
+static int wait_for_backend_closed(xenbus_event_queue* events, char* path)
+{
+   int state;
+
+   TPMFRONT_LOG("Waiting for backend to close..\n");
+   while(1) {
+      state = xenbus_read_integer(path);
+      if ( state < 0)
+     state = XenbusStateUnknown;
+      switch(state) {
+     case XenbusStateUnknown:
+        TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n");
+        return -1;
+     case XenbusStateClosed:
+        TPMFRONT_LOG("Backend Closed\n");
+        return 0;
+     default:
+        xenbus_wait_for_watch(events);
+      }
+   }
+
+}
+
+static int wait_for_backend_state_changed(struct tpmfront_dev* dev,
XenbusState state) {
+   char* err;
+   int ret = 0;
+   xenbus_event_queue events = NULL;
+   char path[512];
+
+   snprintf(path, 512, "%s/state", dev->bepath);
+   /*Setup the watch to wait for the backend */
+   if((err = xenbus_watch_path_token(XBT_NIL, path, path, &events))) {
+      TPMFRONT_ERR("Could not set a watch on %s, error was %s\n", path,
err);
+      free(err);
+      return -1;
+   }
+
+   /* Do the actual wait loop now */
+   switch(state) {
+      case XenbusStateConnected:
+     ret = wait_for_backend_connect(&events, path);
+     break;
+      case XenbusStateClosed:
+     ret = wait_for_backend_closed(&events, path);
+     break;
+      default:
+     break;
+   }
+
+   if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) {
+      TPMFRONT_ERR("Unable to unwatch %s, error was %s, ignoring..\n",
path, err);
+      free(err);
+   }
+   return ret;
+}
+
+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) {
+      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);
+   TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref);
+
+   /*Create event channel */
+   if(evtchn_alloc_unbound(dev->bedomid, tpmfront_handler, dev,
&dev->evtchn)) {
+      TPMFRONT_ERR("Unable to allocate event channel\n");
+      goto error_postmap;
+   }
+   unmask_evtchn(dev->evtchn);
+   TPMFRONT_DEBUG("event channel is %lu\n", (unsigned long) dev->evtchn);
+
+   /* Write the entries to xenstore */
+   if(publish_xenbus(dev)) {
+      goto error_postevtchn;
+   }
+
+   /* Change state to connected */
+   dev->state = XenbusStateConnected;
+
+   /* Tell the backend that we are ready */
+   if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
dev->state))) {
+      TPMFRONT_ERR("Unable to write to xenstore %s/state, value=%u",
dev->nodename, XenbusStateConnected);
+      free(err);
+      goto error;
+   }
+
+   return 0;
+error_postevtchn:
+      mask_evtchn(dev->evtchn);
+      unbind_evtchn(dev->evtchn);
+error_postmap:
+      gnttab_end_access(dev->ring_ref);
+      free_page(dev->tx);
+error:
+   return -1;
+}
+
+struct tpmfront_dev* init_tpmfront(const char* _nodename)
+{
+   struct tpmfront_dev* dev;
+   const char* nodename;
+   char path[512];
+   char* value, *err;
+   unsigned long long ival;
+   int i;
+
+   printk("============= Init TPM Front ================\n");
+
+   dev = malloc(sizeof(struct tpmfront_dev));
+   memset(dev, 0, sizeof(struct tpmfront_dev));
+
+#ifdef HAVE_LIBC
+   dev->fd = -1;
+#endif
+
+   nodename = _nodename ? _nodename : "device/vtpm/0";
+   dev->nodename = strdup(nodename);
+
+   init_waitqueue_head(&dev->waitq);
+
+   /* Get backend domid */
+   snprintf(path, 512, "%s/backend-id", dev->nodename);
+   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;
+   }
+   if(sscanf(value, "%llu", &ival) != 1) {
+      TPMFRONT_ERR("%s has non-integer value (%s)\n", path, value);
+      free(value);
+      goto error;
+   }
+   free(value);
+   dev->bedomid = ival;
+
+   /* Get backend xenstore path */
+   snprintf(path, 512, "%s/backend", dev->nodename);
+   if((err = xenbus_read(XBT_NIL, path, &dev->bepath))) {
+      TPMFRONT_ERR("Unable to read %s during tpmfront initialization!
error = %s\n", path, err);
+      free(err);
+      goto error;
+   }
+
+   /* Create and publish grant reference and event channel */
+   if (tpmfront_connect(dev)) {
+      goto error;
+   }
+
+   /* Wait for backend to connect */
+   if( wait_for_backend_state_changed(dev, XenbusStateConnected)) {
+      goto error;
+   }
+
+   /* Allocate pages that will contain the messages */
+   dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE);
+   if(dev->pages == NULL) {
+      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;
+      }
+   }
+
+   TPMFRONT_LOG("Initialization Completed successfully\n");
+
+   return dev;
+
+error:
+   shutdown_tpmfront(dev);
+   return NULL;
+}
+void shutdown_tpmfront(struct tpmfront_dev* dev)
+{
+   char* err;
+   char path[512];
+   int i;
+   tpmif_tx_request_t* tx;
+   if(dev == NULL) {
+      return;
+   }
+   TPMFRONT_LOG("Shutting down tpmfront\n");
+   /* disconnect */
+   if(dev->state == XenbusStateConnected) {
+      dev->state = XenbusStateClosing;
+      //FIXME: Transaction for this?
+      /* Tell backend we are closing */
+      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
(unsigned int) dev->state))) {
+     free(err);
+      }
+
+      /* Clean up xenstore entries */
+      snprintf(path, 512, "%s/event-channel", dev->nodename);
+      if((err = xenbus_rm(XBT_NIL, path))) {
+     free(err);
+      }
+      snprintf(path, 512, "%s/ring-ref", dev->nodename);
+      if((err = xenbus_rm(XBT_NIL, path))) {
+     free(err);
+      }
+
+      /* Tell backend we are closed */
+      dev->state = XenbusStateClosed;
+      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
(unsigned int) dev->state))) {
+     TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename,
err);
+     free(err);
+      }
+
+      /* 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);
+
+   }
+
+   /* Cleanup memory usage */
+   if(dev->respbuf) {
+      free(dev->respbuf);
+   }
+   if(dev->bepath) {
+      free(dev->bepath);
+   }
+   if(dev->nodename) {
+      free(dev->nodename);
+   }
+   free(dev);
+}
+
+int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t
length)
+{
+   int i;
+   tpmif_tx_request_t* tx = NULL;
+   /* Error Checking */
+   if(dev == NULL || dev->state != XenbusStateConnected) {
+      TPMFRONT_ERR("Tried to send message through disconnected
frontend\n");
+      return -1;
+   }
+
+#ifdef TPMFRONT_PRINT_DEBUG
+   TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length);
+   for(i = 0; i < length; ++i) {
+      if(!(i % 30)) {
+     TPMFRONT_DEBUG_MORE("\n");
+      }
+      TPMFRONT_DEBUG_MORE("%02X ", msg[i]);
+   }
+   TPMFRONT_DEBUG_MORE("\n");
+#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;
+   }
+   dev->waiting = 1;
+   dev->resplen = 0;
+#ifdef HAVE_LIBC
+   if(dev->fd >= 0) {
+      files[dev->fd].read = 0;
+      files[dev->fd].tpmfront.respgot = 0;
+      files[dev->fd].tpmfront.offset = 0;
+   }
+#endif
+   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;
+   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));
+
+   /* Initialize */
+   *msg = NULL;
+   *length = 0;
+
+   /* 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;
+   }
+   /* 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;
+   }
+#ifdef TPMFRONT_PRINT_DEBUG
+   TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned
int) *length);
+   for(i = 0; i < *length; ++i) {
+      if(!(i % 30)) {
+     TPMFRONT_DEBUG_MORE("\n");
+      }
+      TPMFRONT_DEBUG_MORE("%02X ", (*msg)[i]);
+   }
+   TPMFRONT_DEBUG_MORE("\n");
+#endif
+#ifdef HAVE_LIBC
+   if(dev->fd >= 0) {
+      files[dev->fd].tpmfront.respgot = 1;
+   }
+#endif
+quit:
+   return 0;
+}
+
+int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen)
+{
+   int rc;
+   if((rc = tpmfront_send(dev, req, reqlen))) {
+      return rc;
+   }
+   if((rc = tpmfront_recv(dev, resp, resplen))) {
+      return rc;
+   }
+
+   return 0;
+}
+
+#ifdef HAVE_LIBC
+#include <errno.h>
+int tpmfront_open(struct tpmfront_dev* dev)
+{
+   /* Silently prevent multiple opens */
+   if(dev->fd != -1) {
+      return dev->fd;
+   }
+
+   dev->fd = alloc_fd(FTYPE_TPMFRONT);
+   printk("tpmfront_open(%s) -> %d\n", dev->nodename, dev->fd);
+   files[dev->fd].tpmfront.dev = dev;
+   files[dev->fd].tpmfront.offset = 0;
+   files[dev->fd].tpmfront.respgot = 0;
+   return dev->fd;
+}
+
+int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count)
+{
+   int rc;
+   struct tpmfront_dev* dev;
+   dev = files[fd].tpmfront.dev;
+
+   if(count == 0) {
+      return 0;
+   }
+
+   /* Return an error if we are already processing a command */
+   if(dev->waiting) {
+      errno = EINPROGRESS;
+      return -1;
+   }
+   /* Send the command now */
+   if((rc = tpmfront_send(dev, buf, count)) != 0) {
+      errno = EIO;
+      return -1;
+   }
+   return count;
+}
+
+int tpmfront_posix_read(int fd, uint8_t* buf, size_t count)
+{
+   int rc;
+   uint8_t* dummybuf;
+   size_t dummysz;
+   struct tpmfront_dev* dev;
+
+   dev = files[fd].tpmfront.dev;
+
+   if(count == 0) {
+      return 0;
+   }
+
+   /* get the response if we haven't already */
+   if(files[dev->fd].tpmfront.respgot == 0) {
+      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
+     errno = EIO;
+     return -1;
+      }
+   }
+
+   /* handle EOF case */
+   if(files[dev->fd].tpmfront.offset >= dev->resplen) {
+      return 0;
+   }
+
+   /* Compute the number of bytes and do the copy operation */
+   if((rc = min(count, dev->resplen - files[dev->fd].tpmfront.offset))
!= 0) {
+      memcpy(buf, dev->respbuf + files[dev->fd].tpmfront.offset, rc);
+      files[dev->fd].tpmfront.offset += rc;
+   }
+
+   return rc;
+}
+
+int tpmfront_posix_fstat(int fd, struct stat* buf)
+{
+   uint8_t* dummybuf;
+   size_t dummysz;
+   int rc;
+   struct tpmfront_dev* dev = files[fd].tpmfront.dev;
+
+   /* If we have a response waiting, then read it now from the backend
+    * so we can get its length*/
+   if(dev->waiting || (files[dev->fd].read == 1 &&
!files[dev->fd].tpmfront.respgot)) {
+      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
+     errno = EIO;
+     return -1;
+      }
+   }
+
+   buf->st_mode = O_RDWR;
+   buf->st_uid = 0;
+   buf->st_gid = 0;
+   buf->st_size = dev->resplen;
+   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
+
+   return 0;
+}
+
+
+#endif
-- 
1.7.4.4



[-- Attachment #1.2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 1459 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

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

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-17 22:08 [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os Matthew Fioravante
@ 2012-09-17 22:52 ` Samuel Thibault
  2012-09-18 18:24   ` Matthew Fioravante
  2012-09-19 12:07 ` Ian Campbell
  2012-09-26 13:25 ` George Dunlap
  2 siblings, 1 reply; 10+ messages in thread
From: Samuel Thibault @ 2012-09-17 22:52 UTC (permalink / raw)
  To: Matthew Fioravante; +Cc: xen-devel

Hello,

I can not review this since I don't know much about TPM, but the
principle seems sound.

Samuel

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-17 22:52 ` Samuel Thibault
@ 2012-09-18 18:24   ` Matthew Fioravante
  2012-09-26 13:30     ` George Dunlap
  0 siblings, 1 reply; 10+ messages in thread
From: Matthew Fioravante @ 2012-09-18 18:24 UTC (permalink / raw)
  To: Samuel Thibault, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 420 bytes --]

Is there anyone on the dev list that is familiar enough to review it?

I can tell you we have been using all 3 of these drivers internally for
about 2 years now without issue. All of them are basically ports of the
linux drivers to mini-os.

On 09/17/2012 06:52 PM, Samuel Thibault wrote:
> Hello,
>
> I can not review this since I don't know much about TPM, but the
> principle seems sound.
>
> Samuel



[-- Attachment #1.2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 1459 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

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

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-17 22:08 [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os Matthew Fioravante
  2012-09-17 22:52 ` Samuel Thibault
@ 2012-09-19 12:07 ` Ian Campbell
  2012-09-19 14:54   ` Matthew Fioravante
  2012-09-26 13:25 ` George Dunlap
  2 siblings, 1 reply; 10+ messages in thread
From: Ian Campbell @ 2012-09-19 12:07 UTC (permalink / raw)
  To: Matthew Fioravante; +Cc: Samuel Thibault, xen-devel

On Mon, 2012-09-17 at 23:08 +0100, Matthew Fioravante wrote:
> This patch adds 3 new drivers to mini-os.
> 
> tpmfront - paravirtualized tpm frontend driver
> tpmback - paravirtualized tpm backend driver
> tpm_tis - hardware tpm driver
> 
> Unfortunately these drivers were derived from GPL licensed linux kernel
> drivers so they must carry the GPL license.

I notice that you have used GPL v3 here, while the original Linux
versions of these files (I looked at 3.6-rc3)both say:
 * 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
 * License.
i.e. doesn't contain the "or later" wording which would allow an upgrade
to v3. Did all of the copyright holders agree to this relicensing?

>  However, since mini-os now
> supports conditional compilation, hopefully these drivers can be
> included into the xen tree and conditionally removed from non-gpl
> projects. By default they are disabled in the makefile.

Are these drivers useful for other stub domains generally or are they
only really useful in the vtpm stub domains? IOW could this GPL code be
made part of the application instead?

This would allow better segregation between the BSD bits of mini-os and
GPL bits.

> Signed off by: Matthew Fioravante matthew.fioravante@jhuapl.edu

Can you confirm that you have the right to submit his code under this
license, since you are not listed in the copyright I guess that would be
clause B of the DCO:
http://wiki.xen.org/wiki/Submitting_Xen_Patches#Signing_off_a_patch

> diff --git a/extras/mini-os/include/tpm_tis.h
> b/extras/mini-os/include/tpm_tis.h
> --- /dev/null
> +++ b/extras/mini-os/include/tpm_tis.h
> @@ -0,0 +1,63 @@
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * This driver 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, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This driver is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Based upon the files:
> + *  drivers/char/tpm/tpm_tis.c
> + *  drivers/char/tpm/tpm.c
> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
> + */

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-19 12:07 ` Ian Campbell
@ 2012-09-19 14:54   ` Matthew Fioravante
  0 siblings, 0 replies; 10+ messages in thread
From: Matthew Fioravante @ 2012-09-19 14:54 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Samuel Thibault, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 112917 bytes --]

On 09/19/2012 08:07 AM, Ian Campbell wrote:
> On Mon, 2012-09-17 at 23:08 +0100, Matthew Fioravante wrote:
>> This patch adds 3 new drivers to mini-os.
>>
>> tpmfront - paravirtualized tpm frontend driver
>> tpmback - paravirtualized tpm backend driver
>> tpm_tis - hardware tpm driver
>>
>> Unfortunately these drivers were derived from GPL licensed linux kernel
>> drivers so they must carry the GPL license.
> I notice that you have used GPL v3 here, while the original Linux
> versions of these files (I looked at 3.6-rc3)both say:
>  * 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
>  * License.
> i.e. doesn't contain the "or later" wording which would allow an upgrade
> to v3. Did all of the copyright holders agree to this relicensing?
Thank you, that was a really good catch. I meant to use GPL v2 but put
in the wrong text.
>>  However, since mini-os now
>> supports conditional compilation, hopefully these drivers can be
>> included into the xen tree and conditionally removed from non-gpl
>> projects. By default they are disabled in the makefile.
> Are these drivers useful for other stub domains generally or are they
> only really useful in the vtpm stub domains? IOW could this GPL code be
> made part of the application instead?
>
> This would allow better segregation between the BSD bits of mini-os and
> GPL bits.
tpmfront would be useful for any mini-os domain that wants a vtpm.
tpm_tis would be useful for any mini-os domain that wants access to the
physical tpm.

tpmback is only useful for the vtpm system itself. Unless someone else
wants to implement a new vtpm domain, I don't see why they would want to
use this driver.
>> Signed off by: Matthew Fioravante matthew.fioravante@jhuapl.edu
> Can you confirm that you have the right to submit his code under this
> license, since you are not listed in the copyright I guess that would be
> clause B of the DCO:
> http://wiki.xen.org/wiki/Submitting_Xen_Patches#Signing_off_a_patch
I have the rights to submit these patches. The copyright clause and GPL
v2 license were approved by our internal review process and that of our
government sponsor.
>
>> diff --git a/extras/mini-os/include/tpm_tis.h
>> b/extras/mini-os/include/tpm_tis.h
>> --- /dev/null
>> +++ b/extras/mini-os/include/tpm_tis.h
>> @@ -0,0 +1,63 @@
>> +/*
>> + * Copyright (c) 2010-2012 United States Government, as represented by
>> + * the Secretary of Defense.  All rights reserved.
>> + *
>> + * This driver 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, either version 3 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This driver is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Based upon the files:
>> + *  drivers/char/tpm/tpm_tis.c
>> + *  drivers/char/tpm/tpm.c
>> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
>> + */
>
Heres an updated patch with v2

Signed of by Matthew Fioravante matthew.fioravante@jhuapl.edu

diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -22,6 +22,9 @@ CONFIG_QEMU_XS_ARGS ?= n
 CONFIG_TEST ?= n
 CONFIG_PCIFRONT ?= n
 CONFIG_BLKFRONT ?= y
+CONFIG_TPMFRONT ?= n
+CONFIG_TPM_TIS ?= n
+CONFIG_TPMBACK ?= n
 CONFIG_NETFRONT ?= y
 CONFIG_FBFRONT ?= y
 CONFIG_KBDFRONT ?= y
@@ -36,6 +39,9 @@ flags-$(CONFIG_SPARSE_BSS) += -DCONFIG_SPARSE_BSS
 flags-$(CONFIG_QEMU_XS_ARGS) += -DCONFIG_QEMU_XS_ARGS
 flags-$(CONFIG_PCIFRONT) += -DCONFIG_PCIFRONT
 flags-$(CONFIG_BLKFRONT) += -DCONFIG_BLKFRONT
+flags-$(CONFIG_TPMFRONT) += -DCONFIG_TPMFRONT
+flags-$(CONFIG_TPM_TIS) += -DCONFIG_TPM_TIS
+flags-$(CONFIG_TPMBACK) += -DCONFIG_TPMBACK
 flags-$(CONFIG_NETFRONT) += -DCONFIG_NETFRONT
 flags-$(CONFIG_KBDFRONT) += -DCONFIG_KBDFRONT
 flags-$(CONFIG_FBFRONT) += -DCONFIG_FBFRONT
@@ -67,6 +73,9 @@ TARGET := mini-os
 SUBDIRS := lib xenbus console
 
 src-$(CONFIG_BLKFRONT) += blkfront.c
+src-$(CONFIG_TPMFRONT) += tpmfront.c
+src-$(CONFIG_TPM_TIS) += tpm_tis.c
+src-$(CONFIG_TPMBACK) += tpmback.c
 src-y += daytime.c
 src-y += events.c
 src-$(CONFIG_FBFRONT) += fbfront.c
diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h
--- a/extras/mini-os/include/lib.h
+++ b/extras/mini-os/include/lib.h
@@ -142,6 +142,8 @@ enum fd_type {
     FTYPE_FB,
     FTYPE_MEM,
     FTYPE_SAVEFILE,
+    FTYPE_TPMFRONT,
+    FTYPE_TPM_TIS,
 };
 
 LIST_HEAD(evtchn_port_list, evtchn_port_info);
@@ -185,6 +187,20 @@ extern struct file {
     struct {
         struct consfront_dev *dev;
     } cons;
+#ifdef CONFIG_TPMFRONT
+    struct {
+       struct tpmfront_dev *dev;
+       int respgot;
+       off_t offset;
+    } tpmfront;
+#endif
+#ifdef CONFIG_TPM_TIS
+    struct {
+       struct tpm_chip *dev;
+       int respgot;
+       off_t offset;
+    } tpm_tis;
+#endif
 #ifdef CONFIG_XENBUS
         struct {
             /* To each xenbus FD is associated a queue of watch events
for this
diff --git a/extras/mini-os/include/tpm_tis.h
b/extras/mini-os/include/tpm_tis.h
--- /dev/null
+++ b/extras/mini-os/include/tpm_tis.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person
obtaining a copy
+ * of this source file (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.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_tis.c
+ *  drivers/char/tpm/tpm.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#ifndef TPM_TIS_H
+#define TPM_TIS_H
+
+#include <mini-os/types.h>
+#include <mini-os/byteorder.h>
+
+#define TPM_TIS_EN_LOCL0 1
+#define TPM_TIS_EN_LOCL1 (1 << 1)
+#define TPM_TIS_EN_LOCL2 (1 << 2)
+#define TPM_TIS_EN_LOCL3 (1 << 3)
+#define TPM_TIS_EN_LOCL4 (1 << 4)
+#define TPM_TIS_EN_LOCLALL (TPM_TIS_EN_LOCL0 | TPM_TIS_EN_LOCL1  |
TPM_TIS_EN_LOCL2 | TPM_TIS_EN_LOCL3 | TPM_TIS_EN_LOCL4)
+#define TPM_TIS_LOCL_INT_TO_FLAG(x) (1 << x)
+#define TPM_BASEADDR 0xFED40000
+#define TPM_PROBE_IRQ 0xFFFF
+
+struct tpm_chip;
+
+struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
unsigned int irq);
+void shutdown_tpm_tis(struct tpm_chip* tpm);
+
+int tpm_tis_request_locality(struct tpm_chip* tpm, int locality);
+int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen);
+
+#ifdef HAVE_LIBC
+#include <sys/stat.h>
+#include <fcntl.h>
+/* POSIX IO functions:
+ * use tpm_tis_open() to get a file descriptor to the tpm device
+ * use write() on the fd to send a command to the backend. You must
+ * include the entire command in a single call to write().
+ * use read() on the fd to read the response. You can use
+ * fstat() to get the size of the response and lseek() to seek on it.
+ */
+int tpm_tis_open(struct tpm_chip* tpm);
+int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count);
+int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count);
+int tpm_tis_posix_fstat(int fd, struct stat* buf);
+#endif
+
+#endif
diff --git a/extras/mini-os/include/tpmback.h
b/extras/mini-os/include/tpmback.h
--- /dev/null
+++ b/extras/mini-os/include/tpmback.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person
obtaining a copy
+ * of this source file (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.
+ *
+ * Based upon the files:
+ *  drivers/xen/tpmbk.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <xen/io/tpmif.h>
+#include <xen/io/xenbus.h>
+#include <mini-os/types.h>
+#include <xen/xen.h>
+#ifndef TPMBACK_H
+#define TPMBACK_H
+
+struct tpmcmd {
+   domid_t domid;        /* Domid of the frontend */
+   unsigned int handle;    /* Handle of the frontend */
+   char* uuid;            /* uuid of the tpm interface - allocated
internally, dont free it */
+
+   unsigned int req_len;        /* Size of the command in buf - set by
tpmback driver */
+   uint8_t* req;            /* tpm command bits, allocated by driver,
DON'T FREE IT */
+   unsigned int resp_len;    /* Size of the outgoing command,
+                   you set this before passing the cmd object to
tpmback_resp */
+   uint8_t* resp;        /* Buffer for response - YOU MUST ALLOCATE IT,
YOU MUST ALSO FREE IT */
+};
+typedef struct tpmcmd tpmcmd_t;
+
+/* Initialize the tpm backend driver
+ * @exclusive_domname - This is NULL terminated list of vtpm uuid
strings. If this list
+ *             is non-empty, then only frontend domains with vtpm
uuid's matching
+ *             entries in this list will be allowed to connect.
+ *             Other connections will be immediatly closed.
+ *             Set this argument to NULL to allow any vtpm to connect.
+ */
+void init_tpmback(char** exclusive_uuids);
+/* Shutdown tpm backend driver */
+void shutdown_tpmback(void);
+
+/* Blocks until a tpm command is sent from any front end.
+ * Returns a pointer to the tpm command to handle.
+ * Do not try to free this pointer or the req buffer
+ * This function will return NULL if the tpm backend driver
+ * is shutdown or any other error occurs */
+tpmcmd_t* tpmback_req_any(void);
+
+/* Blocks until a tpm command from the frontend at domid/handle
+ * is sent.
+ * Returns NULL if domid/handle is not connected, tpmback is
+ * shutdown or shutting down, or if there is an error
+ */
+tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle);
+
+/* Send the response to the tpm command back to the frontend
+ * This function will free the tpmcmd object, but you must free the resp
+ * buffer yourself */
+void tpmback_resp(tpmcmd_t* tpmcmd);
+
+/* Waits for the first frontend to connect and then sets domid and
handle appropriately.
+ * If one or more frontends are already connected, this will set domid
and handle to one
+ * of them arbitrarily. The main use for this function is to wait until
a single
+ * frontend connection has occured.
+ * returns 0 on success, non-zero on failure */
+int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int
*handle);
+
+/* returns the number of frontends connected */
+int tpmback_num_frontends(void);
+
+/* Returns the uuid of the specified frontend, NULL on error */
+char* tpmback_get_uuid(domid_t domid, unsigned int handle);
+
+/* Specify a function to call when a new tpm device connects */
+void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int));
+
+/* Specify a function to call when a tpm device disconnects */
+void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int));
+
+//Not Implemented
+void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int));
+void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int));
+
+#endif
diff --git a/extras/mini-os/include/tpmfront.h
b/extras/mini-os/include/tpmfront.h
--- /dev/null
+++ b/extras/mini-os/include/tpmfront.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person
obtaining a copy
+ * of this source file (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.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_vtpm.c
+ *  drivers/char/tpm/tpm_xen.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#ifndef TPMFRONT_H
+#define TPMFRONT_H
+
+#include <mini-os/types.h>
+#include <mini-os/os.h>
+#include <mini-os/events.h>
+#include <mini-os/wait.h>
+#include <xen/xen.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/tpmif.h>
+
+struct tpmfront_dev {
+   grant_ref_t ring_ref;
+   evtchn_port_t evtchn;
+
+   tpmif_tx_interface_t* tx;
+
+   void** pages;
+
+   domid_t bedomid;
+   char* nodename;
+   char* bepath;
+
+   XenbusState state;
+
+   uint8_t waiting;
+   struct wait_queue_head waitq;
+
+   uint8_t* respbuf;
+   size_t resplen;
+
+#ifdef HAVE_LIBC
+   int fd;
+#endif
+
+};
+
+
+/*Initialize frontend */
+struct tpmfront_dev* init_tpmfront(const char* nodename);
+/*Shutdown frontend */
+void shutdown_tpmfront(struct tpmfront_dev* dev);
+
+/* Send a tpm command to the backend and wait for the response
+ *
+ * @dev - frontend device
+ * @req - request buffer
+ * @reqlen - length of request buffer
+ * @resp - *resp will be set to internal response buffer, don't free
it! Value is undefined on error
+ * @resplen - *resplen will be set to the length of the response. Value
is undefined on error
+ *
+ * returns 0 on success, non zero on failure.
+ * */
+int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen);
+
+#ifdef HAVE_LIBC
+#include <sys/stat.h>
+/* POSIX IO functions:
+ * use tpmfront_open() to get a file descriptor to the tpm device
+ * use write() on the fd to send a command to the backend. You must
+ * include the entire command in a single call to write().
+ * use read() on the fd to read the response. You can use
+ * fstat() to get the size of the response and lseek() to seek on it.
+ */
+int tpmfront_open(struct tpmfront_dev* dev);
+int tpmfront_posix_read(int fd, uint8_t* buf, size_t count);
+int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count);
+int tpmfront_posix_fstat(int fd, struct stat* buf);
+#endif
+
+
+#endif
diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
--- a/extras/mini-os/lib/sys.c
+++ b/extras/mini-os/lib/sys.c
@@ -27,6 +27,8 @@
 #include <netfront.h>
 #include <blkfront.h>
 #include <fbfront.h>
+#include <tpmfront.h>
+#include <tpm_tis.h>
 #include <xenbus.h>
 #include <xenstore.h>
 
@@ -294,6 +296,16 @@ int read(int fd, void *buf, size_t nbytes)
         return blkfront_posix_read(fd, buf, nbytes);
         }
 #endif
+#ifdef CONFIG_TPMFRONT
+        case FTYPE_TPMFRONT: {
+        return tpmfront_posix_read(fd, buf, nbytes);
+        }
+#endif
+#ifdef CONFIG_TPM_TIS
+        case FTYPE_TPM_TIS: {
+        return tpm_tis_posix_read(fd, buf, nbytes);
+        }
+#endif
     default:
         break;
     }
@@ -330,6 +342,14 @@ int write(int fd, const void *buf, size_t nbytes)
     case FTYPE_BLK:
         return blkfront_posix_write(fd, buf, nbytes);
 #endif
+#ifdef CONFIG_TPMFRONT
+    case FTYPE_TPMFRONT:
+        return tpmfront_posix_write(fd, buf, nbytes);
+#endif
+#ifdef CONFIG_TPM_TIS
+    case FTYPE_TPM_TIS:
+        return tpm_tis_posix_write(fd, buf, nbytes);
+#endif
     default:
         break;
     }
@@ -341,8 +361,16 @@ int write(int fd, const void *buf, size_t nbytes)
 off_t lseek(int fd, off_t offset, int whence)
 {
     switch(files[fd].type) {
+#if defined(CONFIG_BLKFRONT) || defined(CONFIG_TPMFRONT) ||
defined(CONFIG_TPM_TIS)
 #ifdef CONFIG_BLKFRONT
        case FTYPE_BLK:
+#endif
+#ifdef CONFIG_TPMFRNT
+       case FTYPE_TPMFRONT:
+#endif
+#ifdef CONFIG_TPM_TIS
+       case FTYPE_TPM_TIS:
+#endif
       switch (whence) {
          case SEEK_SET:
         files[fd].file.offset = offset;
@@ -420,6 +448,18 @@ int close(int fd)
         files[fd].type = FTYPE_NONE;
         return 0;
 #endif
+#ifdef CONFIG_TPMFRONT
+    case FTYPE_TPMFRONT:
+            shutdown_tpmfront(files[fd].tpmfront.dev);
+        files[fd].type = FTYPE_NONE;
+        return 0;
+#endif
+#ifdef CONFIG_TPM_TIS
+    case FTYPE_TPM_TIS:
+            shutdown_tpm_tis(files[fd].tpm_tis.dev);
+        files[fd].type = FTYPE_NONE;
+        return 0;
+#endif
 #ifdef CONFIG_KBDFRONT
     case FTYPE_KBD:
             shutdown_kbdfront(files[fd].kbd.dev);
@@ -489,6 +529,14 @@ int fstat(int fd, struct stat *buf)
     case FTYPE_BLK:
        return blkfront_posix_fstat(fd, buf);
 #endif
+#ifdef CONFIG_TPMFRONT
+    case FTYPE_TPMFRONT:
+       return tpmfront_posix_fstat(fd, buf);
+#endif
+#ifdef CONFIG_TPM_TIS
+    case FTYPE_TPM_TIS:
+       return tpm_tis_posix_fstat(fd, buf);
+#endif
     default:
         break;
     }
diff --git a/extras/mini-os/tpm_tis.c b/extras/mini-os/tpm_tis.c
--- /dev/null
+++ b/extras/mini-os/tpm_tis.c
@@ -0,0 +1,1355 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person
obtaining a copy
+ * of this source file (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.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_tis.c
+ *  drivers/char/tpm/tpm.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <mini-os/ioremap.h>
+#include <mini-os/iorw.h>
+#include <mini-os/tpm_tis.h>
+#include <mini-os/os.h>
+#include <mini-os/sched.h>
+#include <mini-os/byteorder.h>
+#include <mini-os/events.h>
+#include <mini-os/wait.h>
+#include <mini-os/xmalloc.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#ifndef min
+    #define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
+#endif
+
+#define TPM_HEADER_SIZE 10
+
+#define TPM_BUFSIZE 2048
+
+struct tpm_input_header {
+        uint16_t  tag;
+        uint32_t  length;
+        uint32_t  ordinal;
+}__attribute__((packed));
+
+struct tpm_output_header {
+        uint16_t  tag;
+        uint32_t  length;
+        uint32_t  return_code;
+}__attribute__((packed));
+
+struct  stclear_flags_t {
+        uint16_t  tag;
+        uint8_t      deactivated;
+        uint8_t      disableForceClear;
+        uint8_t      physicalPresence;
+        uint8_t      physicalPresenceLock;
+        uint8_t      bGlobalLock;
+}__attribute__((packed));
+
+struct  tpm_version_t {
+        uint8_t      Major;
+        uint8_t      Minor;
+        uint8_t      revMajor;
+        uint8_t      revMinor;
+}__attribute__((packed));
+
+struct  tpm_version_1_2_t {
+        uint16_t  tag;
+        uint8_t      Major;
+        uint8_t      Minor;
+        uint8_t      revMajor;
+        uint8_t      revMinor;
+}__attribute__((packed));
+
+struct  timeout_t {
+        uint32_t  a;
+        uint32_t  b;
+        uint32_t  c;
+        uint32_t  d;
+}__attribute__((packed));
+
+struct duration_t {
+        uint32_t  tpm_short;
+        uint32_t  tpm_medium;
+        uint32_t  tpm_long;
+}__attribute__((packed));
+
+struct permanent_flags_t {
+        uint16_t  tag;
+        uint8_t      disable;
+        uint8_t      ownership;
+        uint8_t      deactivated;
+        uint8_t      readPubek;
+        uint8_t      disableOwnerClear;
+        uint8_t      allowMaintenance;
+        uint8_t      physicalPresenceLifetimeLock;
+        uint8_t      physicalPresenceHWEnable;
+        uint8_t      physicalPresenceCMDEnable;
+        uint8_t      CEKPUsed;
+        uint8_t      TPMpost;
+        uint8_t      TPMpostLock;
+        uint8_t      FIPS;
+        uint8_t      operator;
+        uint8_t      enableRevokeEK;
+        uint8_t      nvLocked;
+        uint8_t      readSRKPub;
+        uint8_t      tpmEstablished;
+        uint8_t      maintenanceDone;
+        uint8_t      disableFullDALogicInfo;
+}__attribute__((packed));
+
+typedef union {
+        struct  permanent_flags_t perm_flags;
+        struct  stclear_flags_t stclear_flags;
+        bool    owned;
+        uint32_t  num_pcrs;
+        struct  tpm_version_t   tpm_version;
+        struct  tpm_version_1_2_t tpm_version_1_2;
+        uint32_t  manufacturer_id;
+        struct timeout_t  timeout;
+        struct duration_t duration;
+} cap_t;
+
+struct  tpm_getcap_params_in {
+        uint32_t  cap;
+        uint32_t  subcap_size;
+        uint32_t  subcap;
+}__attribute__((packed));
+
+struct  tpm_getcap_params_out {
+        uint32_t  cap_size;
+        cap_t   cap;
+}__attribute__((packed));
+
+struct  tpm_readpubek_params_out {
+        uint8_t      algorithm[4];
+        uint8_t      encscheme[2];
+        uint8_t      sigscheme[2];
+        uint32_t  paramsize;
+        uint8_t      parameters[12]; /*assuming RSA*/
+        uint32_t  keysize;
+        uint8_t      modulus[256];
+        uint8_t      checksum[20];
+}__attribute__((packed));
+
+typedef union {
+        struct  tpm_input_header in;
+        struct  tpm_output_header out;
+} tpm_cmd_header;
+
+#define TPM_DIGEST_SIZE 20
+struct tpm_pcrread_out {
+        uint8_t      pcr_result[TPM_DIGEST_SIZE];
+}__attribute__((packed));
+
+struct tpm_pcrread_in {
+        uint32_t  pcr_idx;
+}__attribute__((packed));
+
+struct tpm_pcrextend_in {
+        uint32_t  pcr_idx;
+        uint8_t      hash[TPM_DIGEST_SIZE];
+}__attribute__((packed));
+
+typedef union {
+        struct  tpm_getcap_params_out getcap_out;
+        struct  tpm_readpubek_params_out readpubek_out;
+        uint8_t      readpubek_out_buffer[sizeof(struct
tpm_readpubek_params_out)];
+        struct  tpm_getcap_params_in getcap_in;
+        struct  tpm_pcrread_in  pcrread_in;
+        struct  tpm_pcrread_out pcrread_out;
+        struct  tpm_pcrextend_in pcrextend_in;
+} tpm_cmd_params;
+
+struct tpm_cmd_t {
+        tpm_cmd_header  header;
+        tpm_cmd_params  params;
+}__attribute__((packed));
+
+
+enum tpm_duration {
+   TPM_SHORT = 0,
+   TPM_MEDIUM = 1,
+   TPM_LONG = 2,
+   TPM_UNDEFINED,
+};
+
+#define TPM_MAX_ORDINAL 243
+#define TPM_MAX_PROTECTED_ORDINAL 12
+#define TPM_PROTECTED_ORDINAL_MASK 0xFF
+
+extern const uint8_t
tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL];
+extern const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL];
+
+#define TPM_DIGEST_SIZE 20
+#define TPM_ERROR_SIZE 10
+#define TPM_RET_CODE_IDX 6
+
+/* tpm_capabilities */
+#define TPM_CAP_FLAG cpu_to_be32(4)
+#define TPM_CAP_PROP cpu_to_be32(5)
+#define CAP_VERSION_1_1 cpu_to_be32(0x06)
+#define CAP_VERSION_1_2 cpu_to_be32(0x1A)
+
+/* tpm_sub_capabilities */
+#define TPM_CAP_PROP_PCR cpu_to_be32(0x101)
+#define TPM_CAP_PROP_MANUFACTURER cpu_to_be32(0x103)
+#define TPM_CAP_FLAG_PERM cpu_to_be32(0x108)
+#define TPM_CAP_FLAG_VOL cpu_to_be32(0x109)
+#define TPM_CAP_PROP_OWNER cpu_to_be32(0x111)
+#define TPM_CAP_PROP_TIS_TIMEOUT cpu_to_be32(0x115)
+#define TPM_CAP_PROP_TIS_DURATION cpu_to_be32(0x120)
+
+
+#define TPM_INTERNAL_RESULT_SIZE 200
+#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
+#define TPM_ORD_GET_CAP cpu_to_be32(101)
+
+extern const struct tpm_input_header tpm_getcap_header;
+
+
+
+const uint8_t tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
+   TPM_UNDEFINED,          /* 0 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 5 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 10 */
+   TPM_SHORT,
+};
+
+const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
+   TPM_UNDEFINED,          /* 0 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 5 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 10 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_LONG,
+   TPM_LONG,
+   TPM_MEDIUM,             /* 15 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_LONG,
+   TPM_SHORT,              /* 20 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_SHORT,              /* 25 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,             /* 30 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 35 */
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 40 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 45 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_LONG,
+   TPM_MEDIUM,             /* 50 */
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 55 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 60 */
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,             /* 65 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 70 */
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 75 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_LONG,               /* 80 */
+   TPM_UNDEFINED,
+   TPM_MEDIUM,
+   TPM_LONG,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 85 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 90 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 95 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 100 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 105 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 110 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 115 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_LONG,               /* 120 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_SHORT,              /* 125 */
+   TPM_SHORT,
+   TPM_LONG,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,              /* 130 */
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,          /* 135 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 140 */
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 145 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 150 */
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 155 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 160 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 165 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_LONG,               /* 170 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 175 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_MEDIUM,             /* 180 */
+   TPM_SHORT,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,             /* 185 */
+   TPM_SHORT,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 190 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 195 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 200 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_SHORT,              /* 205 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_MEDIUM,             /* 210 */
+   TPM_UNDEFINED,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,          /* 215 */
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,
+   TPM_SHORT,              /* 220 */
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_SHORT,
+   TPM_UNDEFINED,          /* 225 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 230 */
+   TPM_LONG,
+   TPM_MEDIUM,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,          /* 235 */
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_UNDEFINED,
+   TPM_SHORT,              /* 240 */
+   TPM_UNDEFINED,
+   TPM_MEDIUM,
+};
+
+const struct tpm_input_header tpm_getcap_header = {
+        .tag = TPM_TAG_RQU_COMMAND,
+        .length = cpu_to_be32(22),
+        .ordinal = TPM_ORD_GET_CAP
+};
+
+
+enum tis_access {
+   TPM_ACCESS_VALID = 0x80,
+   TPM_ACCESS_ACTIVE_LOCALITY = 0x20,    /* (R) */
+   TPM_ACCESS_RELINQUISH_LOCALITY = 0x20,/* (W) */
+   TPM_ACCESS_REQUEST_PENDING = 0x04,    /* (W) */
+   TPM_ACCESS_REQUEST_USE = 0x02,    /* (W) */
+};
+
+enum tis_status {
+   TPM_STS_VALID = 0x80,        /* (R) */
+   TPM_STS_COMMAND_READY = 0x40,    /* (R) */
+   TPM_STS_DATA_AVAIL = 0x10,        /* (R) */
+   TPM_STS_DATA_EXPECT = 0x08,        /* (R) */
+   TPM_STS_GO = 0x20,            /* (W) */
+};
+
+enum tis_int_flags {
+   TPM_GLOBAL_INT_ENABLE = 0x80000000,
+   TPM_INTF_BURST_COUNT_STATIC = 0x100,
+   TPM_INTF_CMD_READY_INT = 0x080,
+   TPM_INTF_INT_EDGE_FALLING = 0x040,
+   TPM_INTF_INT_EDGE_RISING = 0x020,
+   TPM_INTF_INT_LEVEL_LOW = 0x010,
+   TPM_INTF_INT_LEVEL_HIGH = 0x008,
+   TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
+   TPM_INTF_STS_VALID_INT = 0x002,
+   TPM_INTF_DATA_AVAIL_INT = 0x001,
+};
+
+enum tis_defaults {
+   TIS_MEM_BASE = 0xFED40000,
+   TIS_MEM_LEN  = 0x5000,
+   TIS_SHORT_TIMEOUT = 750, /*ms*/
+   TIS_LONG_TIMEOUT = 2000, /*2 sec */
+};
+
+#define TPM_TIMEOUT 5
+
+#define TPM_ACCESS(t, l)                   (((uint8_t*)t->pages[l]) +
0x0000)
+#define TPM_INT_ENABLE(t, l)              
((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0008))
+#define TPM_INT_VECTOR(t, l)               (((uint8_t*)t->pages[l]) +
0x000C)
+#define TPM_INT_STATUS(t, l)               (((uint8_t*)t->pages[l]) +
0x0010)
+#define TPM_INTF_CAPS(t, l)               
((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0014))
+#define TPM_STS(t, l)                     
((uint8_t*)(((uint8_t*)t->pages[l]) + 0x0018))
+#define TPM_DATA_FIFO(t, l)                (((uint8_t*)t->pages[l]) +
0x0024)
+
+#define TPM_DID_VID(t, l)                 
((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0F00))
+#define TPM_RID(t, l)                      (((uint8_t*)t->pages[l]) +
0x0F04)
+
+struct tpm_chip {
+   int enabled_localities;
+   int locality;
+   unsigned long baseaddr;
+   uint8_t* pages[5];
+   int did, vid, rid;
+
+   uint8_t data_buffer[TPM_BUFSIZE];
+   int data_len;
+
+   s_time_t timeout_a, timeout_b, timeout_c, timeout_d;
+   s_time_t duration[3];
+
+#ifdef HAVE_LIBC
+   int fd;
+#endif
+
+   unsigned int irq;
+   struct wait_queue_head read_queue;
+   struct wait_queue_head int_queue;
+};
+
+
+static void __init_tpm_chip(struct tpm_chip* tpm) {
+   tpm->enabled_localities = TPM_TIS_EN_LOCLALL;
+   tpm->locality = -1;
+   tpm->baseaddr = 0;
+   tpm->pages[0] = tpm->pages[1] = tpm->pages[2] = tpm->pages[3] =
tpm->pages[4] = NULL;
+   tpm->vid = 0;
+   tpm->did = 0;
+   tpm->irq = 0;
+   init_waitqueue_head(&tpm->read_queue);
+   init_waitqueue_head(&tpm->int_queue);
+
+   tpm->data_len = -1;
+
+#ifdef HAVE_LIBC
+   tpm->fd = -1;
+#endif
+}
+
+/*
+ * Returns max number of nsecs to wait
+ */
+s_time_t tpm_calc_ordinal_duration(struct tpm_chip *chip,
+      uint32_t ordinal)
+{
+   int duration_idx = TPM_UNDEFINED;
+   s_time_t duration = 0;
+
+   if (ordinal < TPM_MAX_ORDINAL)
+      duration_idx = tpm_ordinal_duration[ordinal];
+   else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
+     TPM_MAX_PROTECTED_ORDINAL)
+      duration_idx =
+     tpm_protected_ordinal_duration[ordinal &
+     TPM_PROTECTED_ORDINAL_MASK];
+
+   if (duration_idx != TPM_UNDEFINED) {
+      duration = chip->duration[duration_idx];
+   }
+
+   if (duration <= 0) {
+      return SECONDS(120);
+   }
+   else
+   {
+      return duration;
+   }
+}
+
+
+static int locality_enabled(struct tpm_chip* tpm, int l) {
+   return tpm->enabled_localities & (1 << l);
+}
+
+static int check_locality(struct tpm_chip* tpm, int l) {
+   if(locality_enabled(tpm, l) && (ioread8(TPM_ACCESS(tpm, l)) &
+        (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
+     (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
+      return l;
+   }
+   return -1;
+}
+
+void release_locality(struct tpm_chip* tpm, int l, int force)
+{
+   if (locality_enabled(tpm, l) && (force || (ioread8(TPM_ACCESS(tpm, l)) &
+           (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
+        (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))) {
+      iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_RELINQUISH_LOCALITY);
+   }
+}
+
+int tpm_tis_request_locality(struct tpm_chip* tpm, int l) {
+
+   s_time_t stop;
+   /*Make sure locality is valid */
+   if(!locality_enabled(tpm, l)) {
+      printk("tpm_tis_change_locality() Tried to change to locality %d,
but it is disabled or invalid!\n", l);
+      return -1;
+   }
+   /* Check if we already have the current locality */
+   if(check_locality(tpm, l) >= 0) {
+      return tpm->locality = l;
+   }
+   /* Set the new locality*/
+   iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_REQUEST_USE);
+
+   if(tpm->irq) {
+      /* Wait for interrupt */
+      wait_event_deadline(tpm->int_queue, (check_locality(tpm, l) >=
0), NOW() + tpm->timeout_a);
+
+      /* FIXME: Handle timeout event, should return error in that case */
+      return l;
+   } else {
+      /* Wait for burstcount */
+      stop = NOW() + tpm->timeout_a;
+      do {
+     if(check_locality(tpm, l) >= 0) {
+        return tpm->locality = l;
+     }
+     msleep(TPM_TIMEOUT);
+      } while(NOW() < stop);
+   }
+
+   printk("REQ LOCALITY FAILURE\n");
+   return -1;
+}
+
+static uint8_t tpm_tis_status(struct tpm_chip* tpm) {
+   return ioread8(TPM_STS(tpm, tpm->locality));
+}
+
+/* This causes the current command to be aborted */
+static void tpm_tis_ready(struct tpm_chip* tpm) {
+   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_COMMAND_READY);
+}
+#define tpm_tis_cancel_cmd(v) tpm_tis_ready(v)
+
+static int get_burstcount(struct tpm_chip* tpm) {
+   s_time_t stop;
+   int burstcnt;
+
+   stop = NOW() + tpm->timeout_d;
+   do {
+      burstcnt = ioread8((TPM_STS(tpm, tpm->locality) + 1));
+      burstcnt += ioread8(TPM_STS(tpm, tpm->locality) + 2) << 8;
+
+      if (burstcnt) {
+     return burstcnt;
+      }
+      msleep(TPM_TIMEOUT);
+   } while(NOW() < stop);
+   return -EBUSY;
+}
+
+static int wait_for_stat(struct tpm_chip* tpm, uint8_t mask,
+      unsigned long timeout, struct wait_queue_head* queue) {
+   s_time_t stop;
+   uint8_t status;
+
+   status = tpm_tis_status(tpm);
+   if((status & mask) == mask) {
+      return 0;
+   }
+
+   if(tpm->irq) {
+      wait_event_deadline(*queue, ((tpm_tis_status(tpm) & mask) ==
mask), timeout);
+      /* FIXME: Check for timeout and return -ETIME */
+      return 0;
+   } else {
+      stop = NOW() + timeout;
+      do {
+     msleep(TPM_TIMEOUT);
+     status = tpm_tis_status(tpm);
+     if((status & mask) == mask)
+        return 0;
+      } while( NOW() < stop);
+   }
+   return -ETIME;
+}
+
+static int recv_data(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
+   int size = 0;
+   int burstcnt;
+   while( size < count &&
+     wait_for_stat(tpm,
+        TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+        tpm->timeout_c,
+        &tpm->read_queue)
+     == 0) {
+      burstcnt = get_burstcount(tpm);
+      for(; burstcnt > 0 && size < count; --burstcnt)
+      {
+     buf[size++] = ioread8(TPM_DATA_FIFO(tpm, tpm->locality));
+      }
+   }
+   return size;
+}
+
+int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
+   int size = 0;
+   int expected, status;
+
+   if (count < TPM_HEADER_SIZE) {
+      size = -EIO;
+      goto out;
+   }
+
+   /* read first 10 bytes, including tag, paramsize, and result */
+   if((size =
+        recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
+      printk("Error reading tpm cmd header\n");
+      goto out;
+   }
+
+   expected = be32_to_cpu(*((uint32_t*)(buf + 2)));
+   if(expected > count) {
+      size = -EIO;
+      goto out;
+   }
+
+   if((size += recv_data(tpm, & buf[TPM_HEADER_SIZE],
+           expected - TPM_HEADER_SIZE)) < expected) {
+      printk("Unable to read rest of tpm command size=%d
expected=%d\n", size, expected);
+      size = -ETIME;
+      goto out;
+   }
+
+   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
+   status = tpm_tis_status(tpm);
+   if(status & TPM_STS_DATA_AVAIL) {
+      printk("Error: left over data\n");
+      size = -EIO;
+      goto out;
+   }
+
+out:
+   tpm_tis_ready(tpm);
+   release_locality(tpm, tpm->locality, 0);
+   return size;
+}
+int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) {
+   int rc;
+   int status, burstcnt = 0;
+   int count = 0;
+   uint32_t ordinal;
+
+   if(tpm_tis_request_locality(tpm, tpm->locality) < 0) {
+      return -EBUSY;
+   }
+
+   status = tpm_tis_status(tpm);
+   if((status & TPM_STS_COMMAND_READY) == 0) {
+      tpm_tis_ready(tpm);
+      if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b,
&tpm->int_queue) < 0) {
+     rc = -ETIME;
+     goto out_err;
+      }
+   }
+
+   while(count < len - 1) {
+      burstcnt = get_burstcount(tpm);
+      for(;burstcnt > 0 && count < len -1; --burstcnt) {
+     iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]);
+      }
+
+      wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
+      status = tpm_tis_status(tpm);
+      if((status & TPM_STS_DATA_EXPECT) == 0) {
+     rc = -EIO;
+     goto out_err;
+      }
+   }
+
+   /*Write last byte*/
+   iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]);
+   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue);
+   status = tpm_tis_status(tpm);
+   if((status & TPM_STS_DATA_EXPECT) != 0) {
+      rc = -EIO;
+      goto out_err;
+   }
+
+   /*go and do it*/
+   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO);
+
+   if(tpm->irq) {
+      /*Wait for interrupt */
+      ordinal = be32_to_cpu(*(buf + 6));
+      if(wait_for_stat(tpm,
+           TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+           tpm_calc_ordinal_duration(tpm, ordinal),
+           &tpm->read_queue) < 0) {
+     rc = -ETIME;
+     goto out_err;
+      }
+   }
+#ifdef HAVE_LIBC
+   if(tpm->fd >= 0) {
+      files[tpm->fd].read = 0;
+      files[tpm->fd].tpm_tis.respgot = 0;
+      files[tpm->fd].tpm_tis.offset = 0;
+   }
+#endif
+   return len;
+
+out_err:
+   tpm_tis_ready(tpm);
+   release_locality(tpm, tpm->locality, 0);
+   return rc;
+}
+
+static void tpm_tis_irq_handler(evtchn_port_t port, struct pt_regs
*regs, void* data)
+{
+   struct tpm_chip* tpm = data;
+   uint32_t interrupt;
+   int i;
+
+   interrupt = ioread32(TPM_INT_STATUS(tpm, tpm->locality));
+   if(interrupt == 0) {
+      return;
+   }
+
+   if(interrupt & TPM_INTF_DATA_AVAIL_INT) {
+      wake_up(&tpm->read_queue);
+   }
+   if(interrupt & TPM_INTF_LOCALITY_CHANGE_INT) {
+      for(i = 0; i < 5; ++i) {
+     if(check_locality(tpm, i) >= 0) {
+        break;
+     }
+      }
+   }
+   if(interrupt & (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
+        TPM_INTF_CMD_READY_INT)) {
+      wake_up(&tpm->int_queue);
+   }
+
+   /* Clear interrupts handled with TPM_EOI */
+   iowrite32(TPM_INT_STATUS(tpm, tpm->locality), interrupt);
+   ioread32(TPM_INT_STATUS(tpm, tpm->locality));
+   return;
+}
+
+/*
+ * Internal kernel interface to transmit TPM commands
+ */
+static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf,
+      size_t bufsiz)
+{
+   ssize_t rc;
+   uint32_t count, ordinal;
+   s_time_t stop;
+
+   count = be32_to_cpu(*((uint32_t *) (buf + 2)));
+   ordinal = be32_to_cpu(*((uint32_t *) (buf + 6)));
+   if (count == 0)
+      return -ENODATA;
+   if (count > bufsiz) {
+      printk("Error: invalid count value %x %zx \n", count, bufsiz);
+      return -E2BIG;
+   }
+
+   //down(&chip->tpm_mutex);
+
+   if ((rc = tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) {
+      printk("tpm_transmit: tpm_send: error %zd\n", rc);
+      goto out;
+   }
+
+   if (chip->irq)
+      goto out_recv;
+
+   stop = NOW() + tpm_calc_ordinal_duration(chip, ordinal);
+   do {
+      uint8_t status = tpm_tis_status(chip);
+      if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) ==
+        (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
+     goto out_recv;
+
+      if ((status == TPM_STS_COMMAND_READY)) {
+     printk("TPM Error: Operation Canceled\n");
+     rc = -ECANCELED;
+     goto out;
+      }
+
+      msleep(TPM_TIMEOUT);    /* CHECK */
+      rmb();
+   } while (NOW() < stop);
+
+   /* Cancel the command */
+   tpm_tis_cancel_cmd(chip);
+   printk("TPM Operation Timed out\n");
+   rc = -ETIME;
+   goto out;
+
+out_recv:
+   if((rc = tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) {
+      printk("tpm_transmit: tpm_recv: error %d\n", rc);
+   }
+out:
+   //up(&chip->tpm_mutex);
+   return rc;
+}
+
+static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
+                            int len, const char *desc)
+{
+        int err;
+
+        len = tpm_transmit(chip,(uint8_t *) cmd, len);
+        if (len <  0)
+                return len;
+        if (len == TPM_ERROR_SIZE) {
+                err = be32_to_cpu(cmd->header.out.return_code);
+                printk("A TPM error (%d) occurred %s\n", err, desc);
+                return err;
+        }
+        return 0;
+}
+
+void tpm_get_timeouts(struct tpm_chip *chip)
+{
+   struct tpm_cmd_t tpm_cmd;
+   struct timeout_t *timeout_cap;
+   struct duration_t *duration_cap;
+   ssize_t rc;
+   uint32_t timeout;
+
+   tpm_cmd.header.in = tpm_getcap_header;
+   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+
+   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+     "attempting to determine the timeouts")) != 0) {
+      printk("transmit failed %d\n", rc);
+      goto duration;
+   }
+
+   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
+     != 4 * sizeof(uint32_t)) {
+      printk("Out len check failure %lu \n",
be32_to_cpu(tpm_cmd.header.out.length));
+      goto duration;
+   }
+
+   timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
+   /* Don't overwrite default if value is 0 */
+   timeout = be32_to_cpu(timeout_cap->a);
+   if (timeout)
+      chip->timeout_a = MICROSECS(timeout); /*Convert to msec */
+   timeout = be32_to_cpu(timeout_cap->b);
+   if (timeout)
+      chip->timeout_b = MICROSECS(timeout); /*Convert to msec */
+   timeout = be32_to_cpu(timeout_cap->c);
+   if (timeout)
+      chip->timeout_c = MICROSECS(timeout); /*Convert to msec */
+   timeout = be32_to_cpu(timeout_cap->d);
+   if (timeout)
+      chip->timeout_d = MICROSECS(timeout); /*Convert to msec */
+
+duration:
+   tpm_cmd.header.in = tpm_getcap_header;
+   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
+
+   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+     "attempting to determine the durations")) < 0) {
+      return;
+   }
+
+   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
+     != 3 * sizeof(uint32_t)) {
+      return;
+   }
+        duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
+        chip->duration[TPM_SHORT] = be32_to_cpu(duration_cap->tpm_short);
+        /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets
the above
+         * value wrong and apparently reports msecs rather than usecs.
So we
+         * fix up the resulting too-small TPM_SHORT value to make
things work.
+         */
+        if (chip->duration[TPM_SHORT] < 10) {
+       chip->duration[TPM_SHORT] = MILLISECS(chip->duration[TPM_SHORT]);
+    } else {
+       chip->duration[TPM_SHORT] = MICROSECS(chip->duration[TPM_SHORT]);
+    }
+
+        chip->duration[TPM_MEDIUM] =
MICROSECS(be32_to_cpu(duration_cap->tpm_medium));
+        chip->duration[TPM_LONG] =
MICROSECS(be32_to_cpu(duration_cap->tpm_long));
+}
+
+
+
+void tpm_continue_selftest(struct tpm_chip* chip) {
+   uint8_t data[] = {
+      0, 193,                 /* TPM_TAG_RQU_COMMAND */
+      0, 0, 0, 10,            /* length */
+      0, 0, 0, 83,            /* TPM_ORD_GetCapability */
+   };
+
+   tpm_transmit(chip, data, sizeof(data));
+}
+
+ssize_t tpm_getcap(struct tpm_chip *chip, uint32_t subcap_id, cap_t *cap,
+                   const char *desc)
+{
+        struct tpm_cmd_t tpm_cmd;
+        int rc;
+
+        tpm_cmd.header.in = tpm_getcap_header;
+        if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
+                tpm_cmd.params.getcap_in.cap = subcap_id;
+                /*subcap field not necessary */
+                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
+                tpm_cmd.header.in.length -= cpu_to_be32(sizeof(uint32_t));
+        } else {
+                if (subcap_id == TPM_CAP_FLAG_PERM ||
+                    subcap_id == TPM_CAP_FLAG_VOL)
+                        tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
+                else
+                        tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+                tpm_cmd.params.getcap_in.subcap = subcap_id;
+        }
+        rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+        if (!rc)
+                *cap = tpm_cmd.params.getcap_out.cap;
+        return rc;
+}
+
+
+struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
unsigned int irq)
+{
+   int i;
+   unsigned long addr;
+   struct tpm_chip* tpm = NULL;
+   uint32_t didvid;
+   uint32_t intfcaps;
+   uint32_t intmask;
+
+   printk("============= Init TPM TIS Driver ==============\n");
+
+   /*Sanity check the localities input */
+   if(localities & ~TPM_TIS_EN_LOCLALL) {
+      printk("init_tpm_tis() Invalid locality specification! %X\n",
localities);
+      goto abort_egress;
+   }
+
+   printk("IOMEM Machine Base Address: %lX\n", baseaddr);
+
+   /* Create the tpm data structure */
+   tpm = malloc(sizeof(struct tpm_chip));
+   __init_tpm_chip(tpm);
+
+   /* Set the enabled localities - if 0 we leave default as all enabled */
+   if(localities != 0) {
+      tpm->enabled_localities = localities;
+   }
+   printk("Enabled Localities: ");
+   for(i = 0; i < 5; ++i) {
+      if(locality_enabled(tpm, i)) {
+     printk("%d ", i);
+      }
+   }
+   printk("\n");
+
+   /* Set the base machine address */
+   tpm->baseaddr = baseaddr;
+
+   /* Set default timeouts */
+   tpm->timeout_a = MILLISECS(TIS_SHORT_TIMEOUT);
+   tpm->timeout_b = MILLISECS(TIS_LONG_TIMEOUT);
+   tpm->timeout_c = MILLISECS(TIS_SHORT_TIMEOUT);
+   tpm->timeout_d = MILLISECS(TIS_SHORT_TIMEOUT);
+
+   /*Map the mmio pages */
+   addr = tpm->baseaddr;
+   for(i = 0; i < 5; ++i) {
+      if(locality_enabled(tpm, i)) {
+     /* Map the page in now */
+     if((tpm->pages[i] = ioremap_nocache(addr, PAGE_SIZE)) == NULL) {
+        printk("Unable to map iomem page a address %p\n", addr);
+        goto abort_egress;
+     }
+
+     /* Set default locality to the first enabled one */
+     if (tpm->locality < 0) {
+        if(tpm_tis_request_locality(tpm, i) < 0) {
+           printk("Unable to request locality %d??\n", i);
+           goto abort_egress;
+        }
+     }
+      }
+      addr += PAGE_SIZE;
+   }
+
+
+   /* Get the vendor and device ids */
+   didvid = ioread32(TPM_DID_VID(tpm, tpm->locality));
+   tpm->did = didvid >> 16;
+   tpm->vid = didvid & 0xFFFF;
+
+
+   /* Get the revision id */
+   tpm->rid = ioread8(TPM_RID(tpm, tpm->locality));
+
+   printk("1.2 TPM (device-id=0x%X vendor-id = %X rev-id = %X)\n",
tpm->did, tpm->vid, tpm->rid);
+
+   intfcaps = ioread32(TPM_INTF_CAPS(tpm, tpm->locality));
+   printk("TPM interface capabilities (0x%x):\n", intfcaps);
+   if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
+      printk("\tBurst Count Static\n");
+   if (intfcaps & TPM_INTF_CMD_READY_INT)
+      printk("\tCommand Ready Int Support\n");
+   if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
+      printk("\tInterrupt Edge Falling\n");
+   if (intfcaps & TPM_INTF_INT_EDGE_RISING)
+      printk("\tInterrupt Edge Rising\n");
+   if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
+      printk("\tInterrupt Level Low\n");
+   if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
+      printk("\tInterrupt Level High\n");
+   if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
+      printk("\tLocality Change Int Support\n");
+   if (intfcaps & TPM_INTF_STS_VALID_INT)
+      printk("\tSts Valid Int Support\n");
+   if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
+      printk("\tData Avail Int Support\n");
+
+   /*Interupt setup */
+   intmask = ioread32(TPM_INT_ENABLE(tpm, tpm->locality));
+
+   intmask |= TPM_INTF_CMD_READY_INT
+      | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
+      | TPM_INTF_STS_VALID_INT;
+
+   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask);
+
+   /*If interupts are enabled, handle it */
+   if(irq) {
+      if(irq != TPM_PROBE_IRQ) {
+     tpm->irq = irq;
+      } else {
+     /*FIXME add irq probing feature later */
+     printk("IRQ probing not implemented\n");
+      }
+   }
+
+   if(tpm->irq) {
+      iowrite8(TPM_INT_VECTOR(tpm, tpm->locality), tpm->irq);
+
+      if(bind_pirq(tpm->irq, 1, tpm_tis_irq_handler, tpm) != 0) {
+     printk("Unabled to request irq: %u for use\n", tpm->irq);
+     printk("Will use polling mode\n");
+     tpm->irq = 0;
+      } else {
+     /* Clear all existing */
+     iowrite32(TPM_INT_STATUS(tpm, tpm->locality),
ioread32(TPM_INT_STATUS(tpm, tpm->locality)));
+
+     /* Turn on interrupts */
+     iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask |
TPM_GLOBAL_INT_ENABLE);
+      }
+   }
+
+   tpm_get_timeouts(tpm);
+   tpm_continue_selftest(tpm);
+
+
+   return tpm;
+abort_egress:
+   if(tpm != NULL) {
+      shutdown_tpm_tis(tpm);
+   }
+   return NULL;
+}
+
+void shutdown_tpm_tis(struct tpm_chip* tpm){
+   int i;
+
+   printk("Shutting down tpm_tis device\n");
+
+   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), ~TPM_GLOBAL_INT_ENABLE);
+
+   /*Unmap all of the mmio pages */
+   for(i = 0; i < 5; ++i) {
+      if(tpm->pages[i] != NULL) {
+     iounmap(tpm->pages[i], PAGE_SIZE);
+     tpm->pages[i] = NULL;
+      }
+   }
+   free(tpm);
+   return;
+}
+
+
+int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen)
+{
+   if(tpm->locality < 0) {
+      printk("tpm_tis_cmd() failed! locality not set!\n");
+      return -1;
+   }
+   if(reqlen > TPM_BUFSIZE) {
+      reqlen = TPM_BUFSIZE;
+   }
+   memcpy(tpm->data_buffer, req, reqlen);
+   *resplen = tpm_transmit(tpm, tpm->data_buffer, TPM_BUFSIZE);
+
+   *resp = malloc(*resplen);
+   memcpy(*resp, tpm->data_buffer, *resplen);
+   return 0;
+}
+
+#ifdef HAVE_LIBC
+int tpm_tis_open(struct tpm_chip* tpm)
+{
+   /* Silently prevent multiple opens */
+   if(tpm->fd != -1) {
+      return tpm->fd;
+   }
+
+   tpm->fd = alloc_fd(FTYPE_TPM_TIS);
+   printk("tpm_tis_open() -> %d\n", tpm->fd);
+   files[tpm->fd].tpm_tis.dev = tpm;
+   files[tpm->fd].tpm_tis.offset = 0;
+   files[tpm->fd].tpm_tis.respgot = 0;
+   return tpm->fd;
+}
+
+int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count)
+{
+   struct tpm_chip* tpm;
+   tpm = files[fd].tpm_tis.dev;
+
+   if(tpm->locality < 0) {
+      printk("tpm_tis_posix_write() failed! locality not set!\n");
+      errno = EINPROGRESS;
+      return -1;
+   }
+   if(count == 0) {
+      return 0;
+   }
+
+   /* Return an error if we are already processing a command */
+   if(count > TPM_BUFSIZE) {
+      count = TPM_BUFSIZE;
+   }
+   /* Send the command now */
+   memcpy(tpm->data_buffer, buf, count);
+   if((tpm->data_len = tpm_transmit(tpm, tpm->data_buffer,
TPM_BUFSIZE)) < 0) {
+      errno = EIO;
+      return -1;
+   }
+   return count;
+}
+
+int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count)
+{
+   int rc;
+   struct tpm_chip* tpm;
+   tpm = files[fd].tpm_tis.dev;
+
+   if(count == 0) {
+      return 0;
+   }
+
+   /* If there is no tpm resp to read, return EIO */
+   if(tpm->data_len < 0) {
+      errno = EIO;
+      return -1;
+   }
+
+
+   /* Handle EOF case */
+   if(files[fd].tpm_tis.offset >= tpm->data_len) {
+      rc = 0;
+   } else {
+      rc = min(tpm->data_len - files[fd].tpm_tis.offset, count);
+      memcpy(buf, tpm->data_buffer + files[fd].tpm_tis.offset, rc);
+   }
+   files[fd].tpm_tis.offset += rc;
+   /* Reset the data pending flag */
+   return rc;
+}
+int tpm_tis_posix_fstat(int fd, struct stat* buf)
+{
+   struct tpm_chip* tpm;
+   tpm = files[fd].tpm_tis.dev;
+
+   buf->st_mode = O_RDWR;
+   buf->st_uid = 0;
+   buf->st_gid = 0;
+   buf->st_size = be32_to_cpu(*((uint32_t*)(tpm->data_buffer + 2)));
+   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
+   return 0;
+}
+
+
+#endif
diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c
--- /dev/null
+++ b/extras/mini-os/tpmback.c
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person
obtaining a copy
+ * of this source file (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.
+ *
+ * Based upon the files:
+ *  drivers/xen/tpmbk.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <mini-os/os.h>
+#include <mini-os/xenbus.h>
+#include <mini-os/events.h>
+#include <errno.h>
+#include <mini-os/gnttab.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/tpmif.h>
+#include <xen/io/protocols.h>
+#include <mini-os/xmalloc.h>
+#include <time.h>
+#include <mini-os/tpmback.h>
+#include <mini-os/lib.h>
+#include <fcntl.h>
+#include <mini-os/mm.h>
+#include <mini-os/posix/sys/mman.h>
+#include <mini-os/semaphore.h>
+#include <mini-os/wait.h>
+
+
+#ifndef HAVE_LIBC
+#define strtoul simple_strtoul
+#endif
+
+//#define TPMBACK_PRINT_DEBUG
+#ifdef TPMBACK_PRINT_DEBUG
+#define TPMBACK_DEBUG(fmt,...) printk("Tpmback:Debug("__FILE__":%d) "
fmt, __LINE__, ##__VA_ARGS__)
+#define TPMBACK_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
+#else
+#define TPMBACK_DEBUG(fmt,...)
+#endif
+#define TPMBACK_ERR(fmt,...) printk("Tpmback:Error " fmt, ##__VA_ARGS__)
+#define TPMBACK_LOG(fmt,...) printk("Tpmback:Info " fmt, ##__VA_ARGS__)
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+/* Default size of the tpmif array at initialization */
+#define DEF_ARRAY_SIZE 1
+
+/* tpmif and tpmdev flags */
+#define TPMIF_CLOSED 1
+#define TPMIF_REQ_READY 2
+
+struct tpmif {
+   domid_t domid;
+   unsigned int handle;
+
+   char* fe_path;
+   char* fe_state_path;
+
+   /* Locally bound event channel*/
+   evtchn_port_t evtchn;
+
+   /* Shared page */
+   tpmif_tx_interface_t* tx;
+
+   /* pointer to TPMIF_RX_RING_SIZE pages */
+   void** pages;
+
+   enum xenbus_state state;
+   enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
+
+   char* uuid;
+
+   /* state flags */
+   int flags;
+};
+typedef struct tpmif tpmif_t;
+
+struct tpmback_dev {
+
+   tpmif_t** tpmlist;
+   unsigned long num_tpms;
+   unsigned long num_alloc;
+
+   struct gntmap map;
+
+   /* True if at least one tpmif has a request to be handled */
+   int flags;
+
+   /* exclusive domains, see init_tpmback comment in tpmback.h */
+   char** exclusive_uuids;
+
+   xenbus_event_queue events;
+
+   /* Callbacks */
+   void (*open_callback)(domid_t, unsigned int);
+   void (*close_callback)(domid_t, unsigned int);
+   void (*suspend_callback)(domid_t, unsigned int);
+   void (*resume_callback)(domid_t, unsigned int);
+};
+typedef struct tpmback_dev tpmback_dev_t;
+
+enum { EV_NONE, EV_NEWFE, EV_STCHNG } tpm_ev_enum;
+
+/* Global objects */
+static struct thread* eventthread = NULL;
+static tpmback_dev_t gtpmdev = {
+   .tpmlist = NULL,
+   .num_tpms = 0,
+   .num_alloc = 0,
+   .flags = TPMIF_CLOSED,
+   .events = NULL,
+   .open_callback = NULL,
+   .close_callback = NULL,
+   .suspend_callback = NULL,
+   .resume_callback = NULL,
+};
+struct wait_queue_head waitq;
+int globalinit = 0;
+
+/************************************
+ * TPMIF SORTED ARRAY FUNCTIONS
+ * tpmback_dev_t.tpmlist is a sorted array, sorted by domid and then
handle number
+ * Duplicates are not allowed
+ * **********************************/
+
+inline void tpmif_req_ready(tpmif_t* tpmif) {
+   tpmif->flags |= TPMIF_REQ_READY;
+   gtpmdev.flags |= TPMIF_REQ_READY;
+}
+
+inline void tpmdev_check_req(void) {
+   int i;
+   int flags;
+   local_irq_save(flags);
+   for(i = 0; i < gtpmdev.num_tpms; ++i) {
+      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
+     gtpmdev.flags |= TPMIF_REQ_READY;
+     local_irq_restore(flags);
+     return;
+      }
+   }
+   gtpmdev.flags &= ~TPMIF_REQ_READY;
+   local_irq_restore(flags);
+}
+
+inline void tpmif_req_finished(tpmif_t* tpmif) {
+   tpmif->flags &= ~TPMIF_REQ_READY;
+   tpmdev_check_req();
+}
+
+int __get_tpmif_index(int st, int n, domid_t domid, unsigned int handle)
+{
+   int i = st + n /2;
+   tpmif_t* tmp;
+
+   if( n <= 0 )
+      return -1;
+
+   tmp = gtpmdev.tpmlist[i];
+   if(domid == tmp->domid && tmp->handle == handle) {
+      return i;
+   } else if ( (domid < tmp->domid) ||
+     (domid == tmp->domid && handle < tmp->handle)) {
+      return __get_tpmif_index(st, n/2, domid, handle);
+   } else {
+      return __get_tpmif_index(i + 1, n/2 - ((n +1) % 2), domid, handle);
+   }
+}
+
+/* Returns the array index of the tpmif domid/handle. Returns -1 if no
such tpmif exists */
+int get_tpmif_index(domid_t domid, unsigned int handle)
+{
+   int flags;
+   int index;
+   local_irq_save(flags);
+   index = __get_tpmif_index(0, gtpmdev.num_tpms, domid, handle);
+   local_irq_restore(flags);
+   return index;
+}
+
+/* Returns the tpmif domid/handle or NULL if none exists */
+tpmif_t* get_tpmif(domid_t domid, unsigned int handle)
+{
+   int flags;
+   int i;
+   tpmif_t* ret;
+   local_irq_save(flags);
+   i = get_tpmif_index(domid, handle);
+   if (i < 0) {
+      ret = NULL;
+   } else {
+      ret = gtpmdev.tpmlist[i];
+   }
+   local_irq_restore(flags);
+   return ret;
+}
+
+/* Remove the given tpmif. Returns 0 if it was removed, -1 if it was
not removed */
+int remove_tpmif(tpmif_t* tpmif)
+{
+   int i, j;
+   char* err;
+   int flags;
+   local_irq_save(flags);
+
+   /* Find the index in the array if it exists */
+   i = get_tpmif_index(tpmif->domid, tpmif->handle);
+   if (i < 0) {
+      goto error;
+   }
+
+   /* Remove the interface from the list */
+   for(j = i; j < gtpmdev.num_tpms - 1; ++j) {
+      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j+1];
+   }
+   gtpmdev.tpmlist[j] = NULL;
+   --gtpmdev.num_tpms;
+
+   /* If removed tpm was the only ready tpm, then we need to check and
turn off the ready flag */
+   tpmdev_check_req();
+
+   local_irq_restore(flags);
+
+   /* Stop listening for events on this tpm interface */
+   if((err = xenbus_unwatch_path_token(XBT_NIL, tpmif->fe_state_path,
tpmif->fe_state_path))) {
+      TPMBACK_ERR("Unable to unwatch path token `%s' Error was %s
Ignoring..\n", tpmif->fe_state_path, err);
+      free(err);
+   }
+
+   return 0;
+error:
+   local_irq_restore(flags);
+   return -1;
+}
+
+/* Insert tpmif into dev->tpmlist. Returns 0 on success and non zero on
error.
+ * It is an error to insert a tpmif with the same domid and handle
+ * number
+ * as something already in the list */
+int insert_tpmif(tpmif_t* tpmif)
+{
+   int flags;
+   unsigned int i, j;
+   tpmif_t* tmp;
+   char* err;
+
+   local_irq_save(flags);
+
+   /*Check if we need to allocate more space */
+   if (gtpmdev.num_tpms == gtpmdev.num_alloc) {
+      gtpmdev.num_alloc *= 2;
+      gtpmdev.tpmlist = realloc(gtpmdev.tpmlist, gtpmdev.num_alloc);
+   }
+
+   /*Find where to put the new interface */
+   for(i = 0; i < gtpmdev.num_tpms; ++i)
+   {
+      tmp = gtpmdev.tpmlist[i];
+      if(tpmif->domid == tmp->domid && tpmif->handle == tmp->handle) {
+     TPMBACK_ERR("Tried to insert duplicate tpm interface %u/%u\n",
(unsigned int) tpmif->domid, tpmif->handle);
+     goto error;
+      }
+      if((tpmif->domid < tmp->domid) ||
+        (tpmif->domid == tmp->domid && tpmif->handle < tmp->handle)) {
+     break;
+      }
+   }
+
+   /*Shift all the tpm pointers past i down one */
+   for(j = gtpmdev.num_tpms; j > i; --j) {
+      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j-1];
+   }
+
+   /*Add the new interface */
+   gtpmdev.tpmlist[i] = tpmif;
+   ++gtpmdev.num_tpms;
+
+   /*Should not be needed, anything inserted with ready flag is
probably an error */
+   tpmdev_check_req();
+
+   local_irq_restore(flags);
+
+   /*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)))
+   {
+      /* if we got an error here we should carefully remove the
interface and then return */
+      TPMBACK_ERR("Unable to watch path token `%s' Error was %s\n",
tpmif->fe_state_path, err);
+      free(err);
+      remove_tpmif(tpmif);
+      goto error_post_irq;
+   }
+
+   return 0;
+error:
+   local_irq_restore(flags);
+error_post_irq:
+   return -1;
+}
+
+
+/*****************
+ * CHANGE BACKEND STATE
+ * *****************/
+/*Attempts to change the backend state in xenstore
+ * returns 0 on success and non-zero on error */
+int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state)
+{
+   char path[512];
+   char *value;
+   char *err;
+   enum xenbus_state readst;
+   TPMBACK_DEBUG("Backend state change %u/%u from=%d to=%d\n",
(unsigned int) tpmif->domid, tpmif->handle, tpmif->state, state);
+   if (tpmif->state == state)
+      return 0;
+
+   snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int)
tpmif->domid, tpmif->handle);
+
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMBACK_ERR("Unable to read backend state %s, error was %s\n",
path, err);
+      free(err);
+      return -1;
+   }
+   if(sscanf(value, "%d", &readst) != 1) {
+      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
+      free(value);
+      return -1;
+   }
+   free(value);
+
+   /* It's possible that the backend state got updated by hotplug or
something else behind our back */
+   if(readst != tpmif->state) {
+      TPMBACK_DEBUG("tpm interface state was %d but xenstore state was
%d!\n", tpmif->state, readst);
+      tpmif->state = readst;
+   }
+
+   /*If if the state isnt changing, then we dont update xenstore b/c we
dont want to fire extraneous events */
+   if(tpmif->state == state) {
+      return 0;
+   }
+
+   /*update xenstore*/
+   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
tpmif->domid, tpmif->handle);
+   if((err = xenbus_printf(XBT_NIL, path, "state", "%u", state))) {
+      TPMBACK_ERR("Error writing to xenstore %s, error was %s new
state=%d\n", path, err, state);
+      free(err);
+      return -1;
+   }
+
+   tpmif->state = state;
+
+   return 0;
+}
+/**********************************
+ * TPMIF CREATION AND DELETION
+ * *******************************/
+inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   tpmif = malloc(sizeof(*tpmif));
+   tpmif->domid = domid;
+   tpmif->handle = handle;
+   tpmif->fe_path = NULL;
+   tpmif->fe_state_path = NULL;
+   tpmif->state = XenbusStateInitialising;
+   tpmif->status = DISCONNECTED;
+   tpmif->tx = NULL;
+   tpmif->pages = NULL;
+   tpmif->flags = 0;
+   tpmif->uuid = NULL;
+   return tpmif;
+}
+
+void __free_tpmif(tpmif_t* tpmif)
+{
+   if(tpmif->pages) {
+      free(tpmif->pages);
+   }
+   if(tpmif->fe_path) {
+      free(tpmif->fe_path);
+   }
+   if(tpmif->fe_state_path) {
+      free(tpmif->fe_state_path);
+   }
+   if(tpmif->uuid) {
+      free(tpmif->uuid);
+   }
+   free(tpmif);
+}
+/* Creates a new tpm interface, adds it to the sorted array and returns it.
+ * returns NULL on error
+ * If the tpm interface already exists, it is returned*/
+tpmif_t* new_tpmif(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   char* err;
+   char path[512];
+
+   /* Make sure we haven't already created this tpm
+    * Double events can occur */
+   if((tpmif = get_tpmif(domid, handle)) != NULL) {
+      return tpmif;
+   }
+
+   tpmif = __init_tpmif(domid, handle);
+
+   /* Get the uuid from xenstore */
+   snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domid,
handle);
+   if((err = xenbus_read(XBT_NIL, path, &tpmif->uuid))) {
+      TPMBACK_ERR("Error reading %s, Error = %s\n", path, err);
+      free(err);
+      goto error;
+   }
+
+   /* Do the exclusive uuid check now */
+   if(gtpmdev.exclusive_uuids != NULL) {
+      char** ptr;
+
+      /* Check that its in the whitelist */
+      for(ptr = gtpmdev.exclusive_uuids; *ptr != NULL; ++ptr) {
+     if(!strcmp(tpmif->uuid, *ptr)) {
+        break;
+     }
+      }
+      /* If *ptr == NULL then we went through the whole list without a
match, so close the connection */
+      if(*ptr == NULL) {
+     tpmif_change_state(tpmif, XenbusStateClosed);
+     TPMBACK_ERR("Frontend %u/%u tried to connect with invalid
uuid=%s\n", (unsigned int) domid, handle, tpmif->uuid);
+     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;
+   }
+
+   snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int)
domid, handle);
+   if((err = xenbus_read(XBT_NIL, path, &tpmif->fe_path))) {
+      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s),
Error = %s", path, err);
+      free(err);
+      goto error;
+   }
+
+   /*Set the state path */
+   tpmif->fe_state_path = malloc(strlen(tpmif->fe_path) + 7);
+   strcpy(tpmif->fe_state_path, tpmif->fe_path);
+   strcat(tpmif->fe_state_path, "/state");
+
+   if(insert_tpmif(tpmif)) {
+      goto error;
+   }
+   TPMBACK_DEBUG("New tpmif %u/%u\n", (unsigned int) tpmif->domid,
tpmif->handle);
+   /* Do the callback now */
+   if(gtpmdev.open_callback) {
+      gtpmdev.open_callback(tpmif->domid, tpmif->handle);
+   }
+   return tpmif;
+error:
+   __free_tpmif(tpmif);
+   return NULL;
+
+}
+
+/* Removes tpmif from dev->tpmlist and frees it's memory usage */
+void free_tpmif(tpmif_t* tpmif)
+{
+   char* err;
+   char path[512];
+   TPMBACK_DEBUG("Free tpmif %u/%u\n", (unsigned int) tpmif->domid,
tpmif->handle);
+   if(tpmif->flags & TPMIF_CLOSED) {
+      TPMBACK_ERR("Tried to free an instance twice! Theres a bug
somewhere!\n");
+      BUG();
+   }
+   tpmif->flags = TPMIF_CLOSED;
+
+   tpmif_change_state(tpmif, XenbusStateClosing);
+
+   /* Unmap share page and unbind event channel */
+   if(tpmif->status == CONNECTED) {
+      tpmif->status = DISCONNECTING;
+      mask_evtchn(tpmif->evtchn);
+
+      if(gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1)) {
+     TPMBACK_ERR("%u/%u Error occured while trying to unmap shared
page\n", (unsigned int) tpmif->domid, tpmif->handle);
+      }
+
+      unbind_evtchn(tpmif->evtchn);
+   }
+   tpmif->status = DISCONNECTED;
+   tpmif_change_state(tpmif, XenbusStateClosed);
+
+   /* Do the callback now */
+   if(gtpmdev.close_callback) {
+      gtpmdev.close_callback(tpmif->domid, tpmif->handle);
+   }
+
+   /* remove from array */
+   remove_tpmif(tpmif);
+
+   /* Wake up anyone possibly waiting on this interface and let them
exit */
+   wake_up(&waitq);
+   schedule();
+
+   /* Remove the old xenbus entries */
+   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
tpmif->domid, tpmif->handle);
+   if((err = xenbus_rm(XBT_NIL, path))) {
+      TPMBACK_ERR("Error cleaning up xenbus entries path=%s
error=%s\n", path, err);
+      free(err);
+   }
+
+   TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int)
tpmif->domid, tpmif->handle);
+
+   /* free memory */
+   __free_tpmif(tpmif);
+
+}
+
+/**********************
+ * REMAINING TPMBACK FUNCTIONS
+ * ********************/
+
+/*Event channel handler */
+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);
+
+}
+
+/* Connect to frontend */
+int connect_fe(tpmif_t* tpmif)
+{
+   char path[512];
+   char* err, *value;
+   uint32_t domid;
+   grant_ref_t ringref;
+   evtchn_port_t evtchn;
+
+   /* If already connected then quit */
+   if (tpmif->status == CONNECTED) {
+      TPMBACK_DEBUG("%u/%u tried to connect while it was already
connected?\n", (unsigned int) tpmif->domid, tpmif->handle);
+      return 0;
+   }
+
+   /* Fetch the grant reference */
+   snprintf(path, 512, "%s/ring-ref", tpmif->fe_path);
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
Error = %s", path, err);
+      free(err);
+      return -1;
+   }
+   if(sscanf(value, "%d", &ringref) != 1) {
+      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
+      free(value);
+      return -1;
+   }
+   free(value);
+
+
+   /* Fetch the event channel*/
+   snprintf(path, 512, "%s/event-channel", tpmif->fe_path);
+   if((err = xenbus_read(XBT_NIL, path, &value))) {
+      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
Error = %s", path, err);
+      free(err);
+      return -1;
+   }
+   if(sscanf(value, "%d", &evtchn) != 1) {
+      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
+      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) {
+      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)))
+   {
+      TPMBACK_ERR("%u/%u Unable to bind to interdomain event
channel!\n", (unsigned int) tpmif->domid, tpmif->handle);
+      goto error_post_map;
+   }
+   unmask_evtchn(tpmif->evtchn);
+
+   /* Write the ready flag and change status to connected */
+   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
tpmif->domid, tpmif->handle);
+   if((err = xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) {
+      TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n",
(unsigned int) tpmif->domid, tpmif->handle);
+      free(err);
+      goto error_post_evtchn;
+   }
+   tpmif->status = CONNECTED;
+   if((tpmif_change_state(tpmif, XenbusStateConnected))){
+      goto error_post_evtchn;
+   }
+
+   TPMBACK_LOG("Frontend %u/%u connected\n", (unsigned int)
tpmif->domid, tpmif->handle);
+
+   return 0;
+error_post_evtchn:
+   mask_evtchn(tpmif->evtchn);
+   unbind_evtchn(tpmif->evtchn);
+error_post_map:
+   gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1);
+   return -1;
+}
+
+static int frontend_changed(tpmif_t* tpmif)
+{
+   int state = xenbus_read_integer(tpmif->fe_state_path);
+   if(state < 0) {
+      state = XenbusStateUnknown;
+   }
+
+   TPMBACK_DEBUG("Frontend %u/%u state changed to %d\n", (unsigned int)
tpmif->domid, tpmif->handle, state);
+
+   switch (state) {
+      case XenbusStateInitialising:
+      case XenbusStateInitialised:
+     break;
+
+      case XenbusStateConnected:
+     if(connect_fe(tpmif)) {
+        TPMBACK_ERR("Failed to connect to front end %u/%u\n", (unsigned
int) tpmif->domid, tpmif->handle);
+        tpmif_change_state(tpmif, XenbusStateClosed);
+        return -1;
+     }
+     break;
+
+      case XenbusStateClosing:
+     tpmif_change_state(tpmif, XenbusStateClosing);
+     break;
+
+      case XenbusStateUnknown: /* keep it here */
+      case XenbusStateClosed:
+     free_tpmif(tpmif);
+     break;
+
+      default:
+     TPMBACK_DEBUG("BAD STATE CHANGE %u/%u state = %d for tpmif\n",
(unsigned int) tpmif->domid, tpmif->handle, state);
+     return -1;
+   }
+   return 0;
+}
+
+
+/* parses the string that comes out of xenbus_watch_wait_return. */
+static int parse_eventstr(const char* evstr, domid_t* domid, unsigned
int* handle)
+{
+   int ret;
+   char cmd[40];
+   char* err;
+   char* value;
+   unsigned int udomid = 0;
+   tpmif_t* tpmif;
+   /* First check for new frontends, this occurs when
/backend/vtpm/<domid>/<handle> gets created. Note we what the sscanf to
fail on the last %s */
+   if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd)
== 2) {
+      *domid = udomid;
+      /* Make sure the entry exists, if this event triggers because the
entry dissapeared then ignore it */
+      if((err = xenbus_read(XBT_NIL, evstr, &value))) {
+     free(err);
+     return EV_NONE;
+      }
+      free(value);
+      /* Make sure the tpmif entry does not already exist, this should
not happen */
+      if((tpmif = get_tpmif(*domid, *handle)) != NULL) {
+     TPMBACK_DEBUG("Duplicate tpm entries! %u %u\n", tpmif->domid,
tpmif->handle);
+     return EV_NONE;
+      }
+      return EV_NEWFE;
+   } else if((ret = sscanf(evstr,
"/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) == 3) {
+      *domid = udomid;
+      if (!strcmp(cmd, "state"))
+     return EV_STCHNG;
+   }
+   return EV_NONE;
+}
+
+void handle_backend_event(char* evstr) {
+   tpmif_t* tpmif;
+   domid_t domid;
+   unsigned int handle;
+   int event;
+
+   TPMBACK_DEBUG("Xenbus Event: %s\n", evstr);
+
+   event = parse_eventstr(evstr, &domid, &handle);
+
+   switch(event) {
+      case EV_NEWFE:
+     if(new_tpmif(domid, handle) == NULL) {
+        TPMBACK_ERR("Failed to create new tpm instance %u/%u\n",
(unsigned int) domid, handle);
+     }
+     wake_up(&waitq);
+     break;
+      case EV_STCHNG:
+     if((tpmif = get_tpmif(domid, handle))) {
+        frontend_changed(tpmif);
+     } else {
+        TPMBACK_DEBUG("Event Received for non-existant tpm!
instance=%u/%u xenbus_event=%s\n", (unsigned int) domid, handle, evstr);
+     }
+     break;
+   }
+}
+
+/* Runs through the given path and creates events recursively
+ * for all of its children.
+ * @path - xenstore path to scan */
+static void generate_backend_events(const char* path)
+{
+   char* err;
+   int i, len;
+   char **dirs;
+   char *entry;
+
+   if((err = xenbus_ls(XBT_NIL, path, &dirs)) != NULL) {
+      free(err);
+      return;
+   }
+
+   for(i = 0; dirs[i] != NULL; ++i) {
+      len = strlen(path) + strlen(dirs[i]) + 2;
+      entry = malloc(len);
+      snprintf(entry, len, "%s/%s", path, dirs[i]);
+
+      /* Generate and handle event for the entry itself */
+      handle_backend_event(entry);
+
+      /* Do children */
+      generate_backend_events(entry);
+
+      /* Cleanup */
+      free(entry);
+      free(dirs[i]);
+   }
+   free(dirs);
+   return;
+}
+
+char* tpmback_get_uuid(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   if((tpmif = get_tpmif(domid, handle)) == NULL) {
+      TPMBACK_DEBUG("get_uuid() failed, %u/%u is an invalid
frontend\n", (unsigned int) domid, handle);
+      return NULL;
+   }
+
+   return tpmif->uuid;
+}
+
+void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.open_callback = cb;
+}
+void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.close_callback = cb;
+}
+void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.suspend_callback = cb;
+}
+void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int))
+{
+   gtpmdev.resume_callback = cb;
+}
+
+static void event_listener(void)
+{
+   const char* bepath = "backend/vtpm";
+   char **path;
+   char* err;
+
+   /* Setup the backend device watch */
+   if((err = xenbus_watch_path_token(XBT_NIL, bepath, bepath,
&gtpmdev.events)) != NULL) {
+      TPMBACK_ERR("xenbus_watch_path_token(%s) failed with error
%s!\n", bepath, err);
+      free(err);
+      goto egress;
+   }
+
+   /* Check for any frontends that connected before we set the watch.
+    * This is almost guaranteed to happen if both domains are started
+    * immediatly one after the other.
+    * We do this by manually generating events on everything in the backend
+    * path */
+   generate_backend_events(bepath);
+
+   /* Wait and listen for changes in frontend connections */
+   while(1) {
+      path = xenbus_wait_for_watch_return(&gtpmdev.events);
+
+      /*If quit flag was set then exit */
+      if(gtpmdev.flags & TPMIF_CLOSED) {
+     TPMBACK_DEBUG("listener thread got quit event. Exiting..\n");
+     free(path);
+     break;
+      }
+      handle_backend_event(*path);
+      free(path);
+
+   }
+
+   if((err = xenbus_unwatch_path_token(XBT_NIL, bepath, bepath)) != NULL) {
+      free(err);
+   }
+egress:
+   return;
+}
+
+void event_thread(void* p) {
+   event_listener();
+}
+
+void init_tpmback(char** exclusive_uuids)
+{
+   if(!globalinit) {
+      init_waitqueue_head(&waitq);
+      globalinit = 1;
+   }
+   printk("============= Init TPM BACK ================\n");
+   gtpmdev.tpmlist = malloc(sizeof(tpmif_t*) * DEF_ARRAY_SIZE);
+   gtpmdev.num_alloc = DEF_ARRAY_SIZE;
+   gtpmdev.num_tpms = 0;
+   gtpmdev.flags = 0;
+   gtpmdev.exclusive_uuids = exclusive_uuids;
+
+   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
+   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
+
+   eventthread = create_thread("tpmback-listener", event_thread, NULL);
+
+}
+
+void shutdown_tpmback(void)
+{
+   /* Disable callbacks */
+   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
+   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
+
+   TPMBACK_LOG("Shutting down tpm backend\n");
+   /* Set the quit flag */
+   gtpmdev.flags = TPMIF_CLOSED;
+
+   //printk("num tpms is %d\n", gtpmdev.num_tpms);
+   /*Free all backend instances */
+   while(gtpmdev.num_tpms) {
+      free_tpmif(gtpmdev.tpmlist[0]);
+   }
+   free(gtpmdev.tpmlist);
+   gtpmdev.tpmlist = NULL;
+   gtpmdev.num_alloc = 0;
+
+   /* Wake up anyone possibly waiting on the device and let them exit */
+   wake_up(&waitq);
+   schedule();
+}
+
+inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int
handle, char* uuid)
+{
+   tpmcmd->domid = domid;
+   tpmcmd->handle = handle;
+   tpmcmd->uuid = uuid;
+   tpmcmd->req = NULL;
+   tpmcmd->req_len = 0;
+   tpmcmd->resp = NULL;
+   tpmcmd->resp_len = 0;
+}
+
+tpmcmd_t* get_request(tpmif_t* tpmif) {
+   tpmcmd_t* cmd;
+   tpmif_tx_request_t* tx;
+   int offset;
+   int tocopy;
+   int i;
+   uint32_t domid;
+   int flags;
+
+   local_irq_save(flags);
+
+   /* Allocate the cmd object to hold the data */
+   if((cmd = malloc(sizeof(*cmd))) == NULL) {
+      goto error;
+   }
+   init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid);
+
+   tx = &tpmif->tx->ring[0].req;
+   cmd->req_len = tx->size;
+   /* 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);
+
+   }
+
+#ifdef TPMBACK_PRINT_DEBUG
+   TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u",
(unsigned int) tpmif->domid, tpmif->handle, cmd->req_len);
+   for(i = 0; i < cmd->req_len; ++i) {
+      if (!(i % 30)) {
+     TPMBACK_DEBUG_MORE("\n");
+      }
+      TPMBACK_DEBUG_MORE("%02hhX ", cmd->req[i]);
+   }
+   TPMBACK_DEBUG_MORE("\n\n");
+#endif
+
+   local_irq_restore(flags);
+   return cmd;
+error:
+   if(cmd != NULL) {
+      if (cmd->req != NULL) {
+     free(cmd->req);
+     cmd->req = NULL;
+      }
+      free(cmd);
+      cmd = NULL;
+   }
+   local_irq_restore(flags);
+   return NULL;
+
+}
+
+void send_response(tpmcmd_t* cmd, tpmif_t* tpmif)
+{
+   tpmif_tx_request_t* tx;
+   int offset;
+   int i;
+   uint32_t domid;
+   int tocopy;
+   int flags;
+
+   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);
+
+   }
+
+#ifdef TPMBACK_PRINT_DEBUG
+   TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int)
tpmif->domid, tpmif->handle, cmd->resp_len);
+   for(i = 0; i < cmd->resp_len; ++i) {
+      if (!(i % 30)) {
+     TPMBACK_DEBUG_MORE("\n");
+      }
+      TPMBACK_DEBUG_MORE("%02hhX ", cmd->resp[i]);
+   }
+   TPMBACK_DEBUG_MORE("\n\n");
+#endif
+   /* clear the ready flag and send the event channel notice to the
frontend */
+   tpmif_req_finished(tpmif);
+   notify_remote_via_evtchn(tpmif->evtchn);
+error:
+   local_irq_restore(flags);
+   return;
+}
+
+tpmcmd_t* tpmback_req_any(void)
+{
+   int i;
+   /* Block until something has a request */
+   wait_event(waitq, (gtpmdev.flags & (TPMIF_REQ_READY | TPMIF_CLOSED)));
+
+   /* Check if were shutting down */
+   if(gtpmdev.flags & TPMIF_CLOSED) {
+      /* if something was waiting for us to give up the queue so it can
shutdown, let it finish */
+      schedule();
+      return NULL;
+   }
+
+   for(i = 0; i < gtpmdev.num_tpms; ++i) {
+      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
+     return get_request(gtpmdev.tpmlist[i]);
+      }
+   }
+
+   TPMBACK_ERR("backend request ready flag was set but no interfaces
were actually ready\n");
+   return NULL;
+}
+
+tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle)
+{
+   tpmif_t* tpmif;
+   tpmif = get_tpmif(domid, handle);
+   if(tpmif == NULL) {
+      return NULL;
+   }
+
+   wait_event(waitq, (tpmif->flags & (TPMIF_REQ_READY | TPMIF_CLOSED)
|| gtpmdev.flags & TPMIF_CLOSED));
+
+   /* Check if were shutting down */
+   if(tpmif->flags & TPMIF_CLOSED || gtpmdev.flags & TPMIF_CLOSED) {
+      /* if something was waiting for us to give up the queue so it can
free this instance, let it finish */
+      schedule();
+      return NULL;
+   }
+
+   return get_request(tpmif);
+}
+
+void tpmback_resp(tpmcmd_t* tpmcmd)
+{
+   tpmif_t* tpmif;
+
+   /* Get the associated interface, if it doesnt exist then just quit */
+   tpmif = get_tpmif(tpmcmd->domid, tpmcmd->handle);
+   if(tpmif == NULL) {
+      TPMBACK_ERR("Tried to send a reponse to non existant frontend
%u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
+      goto end;
+   }
+
+   if(!(tpmif->flags & TPMIF_REQ_READY)) {
+      TPMBACK_ERR("Tried to send response to a frontend that was not
waiting for one %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
+      goto end;
+   }
+
+   /* Send response to frontend */
+   send_response(tpmcmd, tpmif);
+
+end:
+   if(tpmcmd->req != NULL) {
+      free(tpmcmd->req);
+   }
+   free(tpmcmd);
+   return;
+}
+
+int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int *handle)
+{
+   tpmif_t* tpmif;
+   int flags;
+   wait_event(waitq, ((gtpmdev.num_tpms > 0) || gtpmdev.flags &
TPMIF_CLOSED));
+   if(gtpmdev.flags & TPMIF_CLOSED) {
+      return -1;
+   }
+   local_irq_save(flags);
+   tpmif = gtpmdev.tpmlist[0];
+   *domid = tpmif->domid;
+   *handle = tpmif->handle;
+   local_irq_restore(flags);
+
+   return 0;
+}
+
+int tpmback_num_frontends(void)
+{
+   return gtpmdev.num_tpms;
+}
diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c
--- /dev/null
+++ b/extras/mini-os/tpmfront.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person
obtaining a copy
+ * of this source file (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.
+ *
+ * Based upon the files:
+ *  drivers/char/tpm/tpm_vtpm.c
+ *  drivers/char/tpm/tpm_xen.c
+ * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
+ */
+#include <mini-os/os.h>
+#include <mini-os/xenbus.h>
+#include <mini-os/xmalloc.h>
+#include <mini-os/events.h>
+#include <mini-os/wait.h>
+#include <mini-os/gnttab.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/tpmif.h>
+#include <mini-os/tpmfront.h>
+#include <fcntl.h>
+
+//#define TPMFRONT_PRINT_DEBUG
+#ifdef TPMFRONT_PRINT_DEBUG
+#define TPMFRONT_DEBUG(fmt,...) printk("Tpmfront:Debug("__FILE__":%d) "
fmt, __LINE__, ##__VA_ARGS__)
+#define TPMFRONT_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
+#else
+#define TPMFRONT_DEBUG(fmt,...)
+#endif
+#define TPMFRONT_ERR(fmt,...) printk("Tpmfront:Error " fmt, ##__VA_ARGS__)
+#define TPMFRONT_LOG(fmt,...) printk("Tpmfront:Info " fmt, ##__VA_ARGS__)
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void
*data) {
+   struct tpmfront_dev* dev = (struct tpmfront_dev*) data;
+   /*If we get a response when we didnt make a request, just ignore it */
+   if(!dev->waiting) {
+      return;
+   }
+
+   dev->waiting = 0;
+#ifdef HAVE_LIBC
+   if(dev->fd >= 0) {
+      files[dev->fd].read = 1;
+   }
+#endif
+   wake_up(&dev->waitq);
+}
+
+static int publish_xenbus(struct tpmfront_dev* dev) {
+   xenbus_transaction_t xbt;
+   int retry;
+   char* err;
+   /* Write the grant reference and event channel to xenstore */
+again:
+   if((err = xenbus_transaction_start(&xbt))) {
+      TPMFRONT_ERR("Unable to start xenbus transaction, error was
%s\n", err);
+      free(err);
+      return -1;
+   }
+
+   if((err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
(unsigned int) dev->ring_ref))) {
+      TPMFRONT_ERR("Unable to write %s/ring-ref, error was %s\n",
dev->nodename, err);
+      free(err);
+      goto abort_transaction;
+   }
+
+   if((err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
(unsigned int) dev->evtchn))) {
+      TPMFRONT_ERR("Unable to write %s/event-channel, error was %s\n",
dev->nodename, err);
+      free(err);
+      goto abort_transaction;
+   }
+
+   if((err = xenbus_transaction_end(xbt, 0, &retry))) {
+      TPMFRONT_ERR("Unable to complete xenbus transaction, error was
%s\n", err);
+      free(err);
+      return -1;
+   }
+   if(retry) {
+      goto again;
+   }
+
+   return 0;
+abort_transaction:
+   if((err = xenbus_transaction_end(xbt, 1, &retry))) {
+      free(err);
+   }
+   return -1;
+}
+
+static int wait_for_backend_connect(xenbus_event_queue* events, char* path)
+{
+   int state;
+
+   TPMFRONT_LOG("Waiting for backend connection..\n");
+   /* Wait for the backend to connect */
+   while(1) {
+      state = xenbus_read_integer(path);
+      if ( state < 0)
+     state = XenbusStateUnknown;
+      switch(state) {
+     /* Bad states, we quit with error */
+     case XenbusStateUnknown:
+     case XenbusStateClosing:
+     case XenbusStateClosed:
+        TPMFRONT_ERR("Unable to connect to backend\n");
+        return -1;
+     /* If backend is connected then break out of loop */
+     case XenbusStateConnected:
+        TPMFRONT_LOG("Backend Connected\n");
+        return 0;
+     default:
+        xenbus_wait_for_watch(events);
+      }
+   }
+
+}
+
+static int wait_for_backend_closed(xenbus_event_queue* events, char* path)
+{
+   int state;
+
+   TPMFRONT_LOG("Waiting for backend to close..\n");
+   while(1) {
+      state = xenbus_read_integer(path);
+      if ( state < 0)
+     state = XenbusStateUnknown;
+      switch(state) {
+     case XenbusStateUnknown:
+        TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n");
+        return -1;
+     case XenbusStateClosed:
+        TPMFRONT_LOG("Backend Closed\n");
+        return 0;
+     default:
+        xenbus_wait_for_watch(events);
+      }
+   }
+
+}
+
+static int wait_for_backend_state_changed(struct tpmfront_dev* dev,
XenbusState state) {
+   char* err;
+   int ret = 0;
+   xenbus_event_queue events = NULL;
+   char path[512];
+
+   snprintf(path, 512, "%s/state", dev->bepath);
+   /*Setup the watch to wait for the backend */
+   if((err = xenbus_watch_path_token(XBT_NIL, path, path, &events))) {
+      TPMFRONT_ERR("Could not set a watch on %s, error was %s\n", path,
err);
+      free(err);
+      return -1;
+   }
+
+   /* Do the actual wait loop now */
+   switch(state) {
+      case XenbusStateConnected:
+     ret = wait_for_backend_connect(&events, path);
+     break;
+      case XenbusStateClosed:
+     ret = wait_for_backend_closed(&events, path);
+     break;
+      default:
+     break;
+   }
+
+   if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) {
+      TPMFRONT_ERR("Unable to unwatch %s, error was %s, ignoring..\n",
path, err);
+      free(err);
+   }
+   return ret;
+}
+
+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) {
+      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);
+   TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref);
+
+   /*Create event channel */
+   if(evtchn_alloc_unbound(dev->bedomid, tpmfront_handler, dev,
&dev->evtchn)) {
+      TPMFRONT_ERR("Unable to allocate event channel\n");
+      goto error_postmap;
+   }
+   unmask_evtchn(dev->evtchn);
+   TPMFRONT_DEBUG("event channel is %lu\n", (unsigned long) dev->evtchn);
+
+   /* Write the entries to xenstore */
+   if(publish_xenbus(dev)) {
+      goto error_postevtchn;
+   }
+
+   /* Change state to connected */
+   dev->state = XenbusStateConnected;
+
+   /* Tell the backend that we are ready */
+   if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
dev->state))) {
+      TPMFRONT_ERR("Unable to write to xenstore %s/state, value=%u",
dev->nodename, XenbusStateConnected);
+      free(err);
+      goto error;
+   }
+
+   return 0;
+error_postevtchn:
+      mask_evtchn(dev->evtchn);
+      unbind_evtchn(dev->evtchn);
+error_postmap:
+      gnttab_end_access(dev->ring_ref);
+      free_page(dev->tx);
+error:
+   return -1;
+}
+
+struct tpmfront_dev* init_tpmfront(const char* _nodename)
+{
+   struct tpmfront_dev* dev;
+   const char* nodename;
+   char path[512];
+   char* value, *err;
+   unsigned long long ival;
+   int i;
+
+   printk("============= Init TPM Front ================\n");
+
+   dev = malloc(sizeof(struct tpmfront_dev));
+   memset(dev, 0, sizeof(struct tpmfront_dev));
+
+#ifdef HAVE_LIBC
+   dev->fd = -1;
+#endif
+
+   nodename = _nodename ? _nodename : "device/vtpm/0";
+   dev->nodename = strdup(nodename);
+
+   init_waitqueue_head(&dev->waitq);
+
+   /* Get backend domid */
+   snprintf(path, 512, "%s/backend-id", dev->nodename);
+   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;
+   }
+   if(sscanf(value, "%llu", &ival) != 1) {
+      TPMFRONT_ERR("%s has non-integer value (%s)\n", path, value);
+      free(value);
+      goto error;
+   }
+   free(value);
+   dev->bedomid = ival;
+
+   /* Get backend xenstore path */
+   snprintf(path, 512, "%s/backend", dev->nodename);
+   if((err = xenbus_read(XBT_NIL, path, &dev->bepath))) {
+      TPMFRONT_ERR("Unable to read %s during tpmfront initialization!
error = %s\n", path, err);
+      free(err);
+      goto error;
+   }
+
+   /* Create and publish grant reference and event channel */
+   if (tpmfront_connect(dev)) {
+      goto error;
+   }
+
+   /* Wait for backend to connect */
+   if( wait_for_backend_state_changed(dev, XenbusStateConnected)) {
+      goto error;
+   }
+
+   /* Allocate pages that will contain the messages */
+   dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE);
+   if(dev->pages == NULL) {
+      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;
+      }
+   }
+
+   TPMFRONT_LOG("Initialization Completed successfully\n");
+
+   return dev;
+
+error:
+   shutdown_tpmfront(dev);
+   return NULL;
+}
+void shutdown_tpmfront(struct tpmfront_dev* dev)
+{
+   char* err;
+   char path[512];
+   int i;
+   tpmif_tx_request_t* tx;
+   if(dev == NULL) {
+      return;
+   }
+   TPMFRONT_LOG("Shutting down tpmfront\n");
+   /* disconnect */
+   if(dev->state == XenbusStateConnected) {
+      dev->state = XenbusStateClosing;
+      //FIXME: Transaction for this?
+      /* Tell backend we are closing */
+      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
(unsigned int) dev->state))) {
+     free(err);
+      }
+
+      /* Clean up xenstore entries */
+      snprintf(path, 512, "%s/event-channel", dev->nodename);
+      if((err = xenbus_rm(XBT_NIL, path))) {
+     free(err);
+      }
+      snprintf(path, 512, "%s/ring-ref", dev->nodename);
+      if((err = xenbus_rm(XBT_NIL, path))) {
+     free(err);
+      }
+
+      /* Tell backend we are closed */
+      dev->state = XenbusStateClosed;
+      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
(unsigned int) dev->state))) {
+     TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename,
err);
+     free(err);
+      }
+
+      /* 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);
+
+   }
+
+   /* Cleanup memory usage */
+   if(dev->respbuf) {
+      free(dev->respbuf);
+   }
+   if(dev->bepath) {
+      free(dev->bepath);
+   }
+   if(dev->nodename) {
+      free(dev->nodename);
+   }
+   free(dev);
+}
+
+int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t
length)
+{
+   int i;
+   tpmif_tx_request_t* tx = NULL;
+   /* Error Checking */
+   if(dev == NULL || dev->state != XenbusStateConnected) {
+      TPMFRONT_ERR("Tried to send message through disconnected
frontend\n");
+      return -1;
+   }
+
+#ifdef TPMFRONT_PRINT_DEBUG
+   TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length);
+   for(i = 0; i < length; ++i) {
+      if(!(i % 30)) {
+     TPMFRONT_DEBUG_MORE("\n");
+      }
+      TPMFRONT_DEBUG_MORE("%02X ", msg[i]);
+   }
+   TPMFRONT_DEBUG_MORE("\n");
+#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;
+   }
+   dev->waiting = 1;
+   dev->resplen = 0;
+#ifdef HAVE_LIBC
+   if(dev->fd >= 0) {
+      files[dev->fd].read = 0;
+      files[dev->fd].tpmfront.respgot = 0;
+      files[dev->fd].tpmfront.offset = 0;
+   }
+#endif
+   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;
+   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));
+
+   /* Initialize */
+   *msg = NULL;
+   *length = 0;
+
+   /* 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;
+   }
+   /* 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;
+   }
+#ifdef TPMFRONT_PRINT_DEBUG
+   TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned
int) *length);
+   for(i = 0; i < *length; ++i) {
+      if(!(i % 30)) {
+     TPMFRONT_DEBUG_MORE("\n");
+      }
+      TPMFRONT_DEBUG_MORE("%02X ", (*msg)[i]);
+   }
+   TPMFRONT_DEBUG_MORE("\n");
+#endif
+#ifdef HAVE_LIBC
+   if(dev->fd >= 0) {
+      files[dev->fd].tpmfront.respgot = 1;
+   }
+#endif
+quit:
+   return 0;
+}
+
+int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
uint8_t** resp, size_t* resplen)
+{
+   int rc;
+   if((rc = tpmfront_send(dev, req, reqlen))) {
+      return rc;
+   }
+   if((rc = tpmfront_recv(dev, resp, resplen))) {
+      return rc;
+   }
+
+   return 0;
+}
+
+#ifdef HAVE_LIBC
+#include <errno.h>
+int tpmfront_open(struct tpmfront_dev* dev)
+{
+   /* Silently prevent multiple opens */
+   if(dev->fd != -1) {
+      return dev->fd;
+   }
+
+   dev->fd = alloc_fd(FTYPE_TPMFRONT);
+   printk("tpmfront_open(%s) -> %d\n", dev->nodename, dev->fd);
+   files[dev->fd].tpmfront.dev = dev;
+   files[dev->fd].tpmfront.offset = 0;
+   files[dev->fd].tpmfront.respgot = 0;
+   return dev->fd;
+}
+
+int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count)
+{
+   int rc;
+   struct tpmfront_dev* dev;
+   dev = files[fd].tpmfront.dev;
+
+   if(count == 0) {
+      return 0;
+   }
+
+   /* Return an error if we are already processing a command */
+   if(dev->waiting) {
+      errno = EINPROGRESS;
+      return -1;
+   }
+   /* Send the command now */
+   if((rc = tpmfront_send(dev, buf, count)) != 0) {
+      errno = EIO;
+      return -1;
+   }
+   return count;
+}
+
+int tpmfront_posix_read(int fd, uint8_t* buf, size_t count)
+{
+   int rc;
+   uint8_t* dummybuf;
+   size_t dummysz;
+   struct tpmfront_dev* dev;
+
+   dev = files[fd].tpmfront.dev;
+
+   if(count == 0) {
+      return 0;
+   }
+
+   /* get the response if we haven't already */
+   if(files[dev->fd].tpmfront.respgot == 0) {
+      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
+     errno = EIO;
+     return -1;
+      }
+   }
+
+   /* handle EOF case */
+   if(files[dev->fd].tpmfront.offset >= dev->resplen) {
+      return 0;
+   }
+
+   /* Compute the number of bytes and do the copy operation */
+   if((rc = min(count, dev->resplen - files[dev->fd].tpmfront.offset))
!= 0) {
+      memcpy(buf, dev->respbuf + files[dev->fd].tpmfront.offset, rc);
+      files[dev->fd].tpmfront.offset += rc;
+   }
+
+   return rc;
+}
+
+int tpmfront_posix_fstat(int fd, struct stat* buf)
+{
+   uint8_t* dummybuf;
+   size_t dummysz;
+   int rc;
+   struct tpmfront_dev* dev = files[fd].tpmfront.dev;
+
+   /* If we have a response waiting, then read it now from the backend
+    * so we can get its length*/
+   if(dev->waiting || (files[dev->fd].read == 1 &&
!files[dev->fd].tpmfront.respgot)) {
+      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
+     errno = EIO;
+     return -1;
+      }
+   }
+
+   buf->st_mode = O_RDWR;
+   buf->st_uid = 0;
+   buf->st_gid = 0;
+   buf->st_size = dev->resplen;
+   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
+
+   return 0;
+}
+
+
+#endif





[-- Attachment #1.2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 1459 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

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

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-17 22:08 [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os Matthew Fioravante
  2012-09-17 22:52 ` Samuel Thibault
  2012-09-19 12:07 ` Ian Campbell
@ 2012-09-26 13:25 ` George Dunlap
  2012-09-26 14:29   ` Matthew Fioravante
  2 siblings, 1 reply; 10+ messages in thread
From: George Dunlap @ 2012-09-26 13:25 UTC (permalink / raw)
  To: Matthew Fioravante; +Cc: Samuel Thibault, xen-devel

On Mon, Sep 17, 2012 at 11:08 PM, Matthew Fioravante
<matthew.fioravante@jhuapl.edu> wrote:
> This patch adds 3 new drivers to mini-os.
>
> tpmfront - paravirtualized tpm frontend driver
> tpmback - paravirtualized tpm backend driver
> tpm_tis - hardware tpm driver

Just trying to understand this -- tpmback is so that you can run a
vtpm instance in the stubdom.  But what is tmpfront for?  Is that for
running qemu stub domains?

 -George

>
> Unfortunately these drivers were derived from GPL licensed linux kernel
> drivers so they must carry the GPL license. However, since mini-os now
> supports conditional compilation, hopefully these drivers can be
> included into the xen tree and conditionally removed from non-gpl
> projects. By default they are disabled in the makefile.
>
> Signed off by: Matthew Fioravante matthew.fioravante@jhuapl.edu
>
> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
> --- a/extras/mini-os/Makefile
> +++ b/extras/mini-os/Makefile
> @@ -22,6 +22,9 @@ CONFIG_QEMU_XS_ARGS ?= n
>  CONFIG_TEST ?= n
>  CONFIG_PCIFRONT ?= n
>  CONFIG_BLKFRONT ?= y
> +CONFIG_TPMFRONT ?= n
> +CONFIG_TPM_TIS ?= n
> +CONFIG_TPMBACK ?= n
>  CONFIG_NETFRONT ?= y
>  CONFIG_FBFRONT ?= y
>  CONFIG_KBDFRONT ?= y
> @@ -36,6 +39,9 @@ flags-$(CONFIG_SPARSE_BSS) += -DCONFIG_SPARSE_BSS
>  flags-$(CONFIG_QEMU_XS_ARGS) += -DCONFIG_QEMU_XS_ARGS
>  flags-$(CONFIG_PCIFRONT) += -DCONFIG_PCIFRONT
>  flags-$(CONFIG_BLKFRONT) += -DCONFIG_BLKFRONT
> +flags-$(CONFIG_TPMFRONT) += -DCONFIG_TPMFRONT
> +flags-$(CONFIG_TPM_TIS) += -DCONFIG_TPM_TIS
> +flags-$(CONFIG_TPMBACK) += -DCONFIG_TPMBACK
>  flags-$(CONFIG_NETFRONT) += -DCONFIG_NETFRONT
>  flags-$(CONFIG_KBDFRONT) += -DCONFIG_KBDFRONT
>  flags-$(CONFIG_FBFRONT) += -DCONFIG_FBFRONT
> @@ -67,6 +73,9 @@ TARGET := mini-os
>  SUBDIRS := lib xenbus console
>
>  src-$(CONFIG_BLKFRONT) += blkfront.c
> +src-$(CONFIG_TPMFRONT) += tpmfront.c
> +src-$(CONFIG_TPM_TIS) += tpm_tis.c
> +src-$(CONFIG_TPMBACK) += tpmback.c
>  src-y += daytime.c
>  src-y += events.c
>  src-$(CONFIG_FBFRONT) += fbfront.c
> diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h
> --- a/extras/mini-os/include/lib.h
> +++ b/extras/mini-os/include/lib.h
> @@ -142,6 +142,8 @@ enum fd_type {
>      FTYPE_FB,
>      FTYPE_MEM,
>      FTYPE_SAVEFILE,
> +    FTYPE_TPMFRONT,
> +    FTYPE_TPM_TIS,
>  };
>
>  LIST_HEAD(evtchn_port_list, evtchn_port_info);
> @@ -185,6 +187,20 @@ extern struct file {
>      struct {
>          struct consfront_dev *dev;
>      } cons;
> +#ifdef CONFIG_TPMFRONT
> +    struct {
> +       struct tpmfront_dev *dev;
> +       int respgot;
> +       off_t offset;
> +    } tpmfront;
> +#endif
> +#ifdef CONFIG_TPM_TIS
> +    struct {
> +       struct tpm_chip *dev;
> +       int respgot;
> +       off_t offset;
> +    } tpm_tis;
> +#endif
>  #ifdef CONFIG_XENBUS
>          struct {
>              /* To each xenbus FD is associated a queue of watch events
> for this
> diff --git a/extras/mini-os/include/tpm_tis.h
> b/extras/mini-os/include/tpm_tis.h
> --- /dev/null
> +++ b/extras/mini-os/include/tpm_tis.h
> @@ -0,0 +1,63 @@
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * This driver 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, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This driver is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Based upon the files:
> + *  drivers/char/tpm/tpm_tis.c
> + *  drivers/char/tpm/tpm.c
> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
> + */
> +#ifndef TPM_TIS_H
> +#define TPM_TIS_H
> +
> +#include <mini-os/types.h>
> +#include <mini-os/byteorder.h>
> +
> +#define TPM_TIS_EN_LOCL0 1
> +#define TPM_TIS_EN_LOCL1 (1 << 1)
> +#define TPM_TIS_EN_LOCL2 (1 << 2)
> +#define TPM_TIS_EN_LOCL3 (1 << 3)
> +#define TPM_TIS_EN_LOCL4 (1 << 4)
> +#define TPM_TIS_EN_LOCLALL (TPM_TIS_EN_LOCL0 | TPM_TIS_EN_LOCL1  |
> TPM_TIS_EN_LOCL2 | TPM_TIS_EN_LOCL3 | TPM_TIS_EN_LOCL4)
> +#define TPM_TIS_LOCL_INT_TO_FLAG(x) (1 << x)
> +#define TPM_BASEADDR 0xFED40000
> +#define TPM_PROBE_IRQ 0xFFFF
> +
> +struct tpm_chip;
> +
> +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
> unsigned int irq);
> +void shutdown_tpm_tis(struct tpm_chip* tpm);
> +
> +int tpm_tis_request_locality(struct tpm_chip* tpm, int locality);
> +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
> uint8_t** resp, size_t* resplen);
> +
> +#ifdef HAVE_LIBC
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +/* POSIX IO functions:
> + * use tpm_tis_open() to get a file descriptor to the tpm device
> + * use write() on the fd to send a command to the backend. You must
> + * include the entire command in a single call to write().
> + * use read() on the fd to read the response. You can use
> + * fstat() to get the size of the response and lseek() to seek on it.
> + */
> +int tpm_tis_open(struct tpm_chip* tpm);
> +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count);
> +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count);
> +int tpm_tis_posix_fstat(int fd, struct stat* buf);
> +#endif
> +
> +#endif
> diff --git a/extras/mini-os/include/tpmback.h
> b/extras/mini-os/include/tpmback.h
> --- /dev/null
> +++ b/extras/mini-os/include/tpmback.h
> @@ -0,0 +1,95 @@
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * This driver 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, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This driver is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Based upon the files:
> + *  drivers/xen/tpmbk.c
> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
> + */
> +#include <xen/io/tpmif.h>
> +#include <xen/io/xenbus.h>
> +#include <mini-os/types.h>
> +#include <xen/xen.h>
> +#ifndef TPMBACK_H
> +#define TPMBACK_H
> +
> +struct tpmcmd {
> +   domid_t domid;        /* Domid of the frontend */
> +   unsigned int handle;    /* Handle of the frontend */
> +   char* uuid;            /* uuid of the tpm interface - allocated
> internally, dont free it */
> +
> +   unsigned int req_len;        /* Size of the command in buf - set by
> tpmback driver */
> +   uint8_t* req;            /* tpm command bits, allocated by driver,
> DON'T FREE IT */
> +   unsigned int resp_len;    /* Size of the outgoing command,
> +                   you set this before passing the cmd object to
> tpmback_resp */
> +   uint8_t* resp;        /* Buffer for response - YOU MUST ALLOCATE IT,
> YOU MUST ALSO FREE IT */
> +};
> +typedef struct tpmcmd tpmcmd_t;
> +
> +/* Initialize the tpm backend driver
> + * @exclusive_domname - This is NULL terminated list of vtpm uuid
> strings. If this list
> + *             is non-empty, then only frontend domains with vtpm
> uuid's matching
> + *             entries in this list will be allowed to connect.
> + *             Other connections will be immediatly closed.
> + *             Set this argument to NULL to allow any vtpm to connect.
> + */
> +void init_tpmback(char** exclusive_uuids);
> +/* Shutdown tpm backend driver */
> +void shutdown_tpmback(void);
> +
> +/* Blocks until a tpm command is sent from any front end.
> + * Returns a pointer to the tpm command to handle.
> + * Do not try to free this pointer or the req buffer
> + * This function will return NULL if the tpm backend driver
> + * is shutdown or any other error occurs */
> +tpmcmd_t* tpmback_req_any(void);
> +
> +/* Blocks until a tpm command from the frontend at domid/handle
> + * is sent.
> + * Returns NULL if domid/handle is not connected, tpmback is
> + * shutdown or shutting down, or if there is an error
> + */
> +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle);
> +
> +/* Send the response to the tpm command back to the frontend
> + * This function will free the tpmcmd object, but you must free the resp
> + * buffer yourself */
> +void tpmback_resp(tpmcmd_t* tpmcmd);
> +
> +/* Waits for the first frontend to connect and then sets domid and
> handle appropriately.
> + * If one or more frontends are already connected, this will set domid
> and handle to one
> + * of them arbitrarily. The main use for this function is to wait until
> a single
> + * frontend connection has occured.
> + * returns 0 on success, non-zero on failure */
> +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int
> *handle);
> +
> +/* returns the number of frontends connected */
> +int tpmback_num_frontends(void);
> +
> +/* Returns the uuid of the specified frontend, NULL on error */
> +char* tpmback_get_uuid(domid_t domid, unsigned int handle);
> +
> +/* Specify a function to call when a new tpm device connects */
> +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int));
> +
> +/* Specify a function to call when a tpm device disconnects */
> +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int));
> +
> +//Not Implemented
> +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int));
> +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int));
> +
> +#endif
> diff --git a/extras/mini-os/include/tpmfront.h
> b/extras/mini-os/include/tpmfront.h
> --- /dev/null
> +++ b/extras/mini-os/include/tpmfront.h
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * This driver 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, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This driver is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Based upon the files:
> + *  drivers/char/tpm/tpm_vtpm.c
> + *  drivers/char/tpm/tpm_xen.c
> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
> + */
> +#ifndef TPMFRONT_H
> +#define TPMFRONT_H
> +
> +#include <mini-os/types.h>
> +#include <mini-os/os.h>
> +#include <mini-os/events.h>
> +#include <mini-os/wait.h>
> +#include <xen/xen.h>
> +#include <xen/io/xenbus.h>
> +#include <xen/io/tpmif.h>
> +
> +struct tpmfront_dev {
> +   grant_ref_t ring_ref;
> +   evtchn_port_t evtchn;
> +
> +   tpmif_tx_interface_t* tx;
> +
> +   void** pages;
> +
> +   domid_t bedomid;
> +   char* nodename;
> +   char* bepath;
> +
> +   XenbusState state;
> +
> +   uint8_t waiting;
> +   struct wait_queue_head waitq;
> +
> +   uint8_t* respbuf;
> +   size_t resplen;
> +
> +#ifdef HAVE_LIBC
> +   int fd;
> +#endif
> +
> +};
> +
> +
> +/*Initialize frontend */
> +struct tpmfront_dev* init_tpmfront(const char* nodename);
> +/*Shutdown frontend */
> +void shutdown_tpmfront(struct tpmfront_dev* dev);
> +
> +/* Send a tpm command to the backend and wait for the response
> + *
> + * @dev - frontend device
> + * @req - request buffer
> + * @reqlen - length of request buffer
> + * @resp - *resp will be set to internal response buffer, don't free
> it! Value is undefined on error
> + * @resplen - *resplen will be set to the length of the response. Value
> is undefined on error
> + *
> + * returns 0 on success, non zero on failure.
> + * */
> +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
> uint8_t** resp, size_t* resplen);
> +
> +#ifdef HAVE_LIBC
> +#include <sys/stat.h>
> +/* POSIX IO functions:
> + * use tpmfront_open() to get a file descriptor to the tpm device
> + * use write() on the fd to send a command to the backend. You must
> + * include the entire command in a single call to write().
> + * use read() on the fd to read the response. You can use
> + * fstat() to get the size of the response and lseek() to seek on it.
> + */
> +int tpmfront_open(struct tpmfront_dev* dev);
> +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count);
> +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count);
> +int tpmfront_posix_fstat(int fd, struct stat* buf);
> +#endif
> +
> +
> +#endif
> diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
> --- a/extras/mini-os/lib/sys.c
> +++ b/extras/mini-os/lib/sys.c
> @@ -27,6 +27,8 @@
>  #include <netfront.h>
>  #include <blkfront.h>
>  #include <fbfront.h>
> +#include <tpmfront.h>
> +#include <tpm_tis.h>
>  #include <xenbus.h>
>  #include <xenstore.h>
>
> @@ -294,6 +296,16 @@ int read(int fd, void *buf, size_t nbytes)
>          return blkfront_posix_read(fd, buf, nbytes);
>          }
>  #endif
> +#ifdef CONFIG_TPMFRONT
> +        case FTYPE_TPMFRONT: {
> +        return tpmfront_posix_read(fd, buf, nbytes);
> +        }
> +#endif
> +#ifdef CONFIG_TPM_TIS
> +        case FTYPE_TPM_TIS: {
> +        return tpm_tis_posix_read(fd, buf, nbytes);
> +        }
> +#endif
>      default:
>          break;
>      }
> @@ -330,6 +342,14 @@ int write(int fd, const void *buf, size_t nbytes)
>      case FTYPE_BLK:
>          return blkfront_posix_write(fd, buf, nbytes);
>  #endif
> +#ifdef CONFIG_TPMFRONT
> +    case FTYPE_TPMFRONT:
> +        return tpmfront_posix_write(fd, buf, nbytes);
> +#endif
> +#ifdef CONFIG_TPM_TIS
> +    case FTYPE_TPM_TIS:
> +        return tpm_tis_posix_write(fd, buf, nbytes);
> +#endif
>      default:
>          break;
>      }
> @@ -341,8 +361,16 @@ int write(int fd, const void *buf, size_t nbytes)
>  off_t lseek(int fd, off_t offset, int whence)
>  {
>      switch(files[fd].type) {
> +#if defined(CONFIG_BLKFRONT) || defined(CONFIG_TPMFRONT) ||
> defined(CONFIG_TPM_TIS)
>  #ifdef CONFIG_BLKFRONT
>         case FTYPE_BLK:
> +#endif
> +#ifdef CONFIG_TPMFRNT
> +       case FTYPE_TPMFRONT:
> +#endif
> +#ifdef CONFIG_TPM_TIS
> +       case FTYPE_TPM_TIS:
> +#endif
>        switch (whence) {
>           case SEEK_SET:
>          files[fd].file.offset = offset;
> @@ -420,6 +448,18 @@ int close(int fd)
>          files[fd].type = FTYPE_NONE;
>          return 0;
>  #endif
> +#ifdef CONFIG_TPMFRONT
> +    case FTYPE_TPMFRONT:
> +            shutdown_tpmfront(files[fd].tpmfront.dev);
> +        files[fd].type = FTYPE_NONE;
> +        return 0;
> +#endif
> +#ifdef CONFIG_TPM_TIS
> +    case FTYPE_TPM_TIS:
> +            shutdown_tpm_tis(files[fd].tpm_tis.dev);
> +        files[fd].type = FTYPE_NONE;
> +        return 0;
> +#endif
>  #ifdef CONFIG_KBDFRONT
>      case FTYPE_KBD:
>              shutdown_kbdfront(files[fd].kbd.dev);
> @@ -489,6 +529,14 @@ int fstat(int fd, struct stat *buf)
>      case FTYPE_BLK:
>         return blkfront_posix_fstat(fd, buf);
>  #endif
> +#ifdef CONFIG_TPMFRONT
> +    case FTYPE_TPMFRONT:
> +       return tpmfront_posix_fstat(fd, buf);
> +#endif
> +#ifdef CONFIG_TPM_TIS
> +    case FTYPE_TPM_TIS:
> +       return tpm_tis_posix_fstat(fd, buf);
> +#endif
>      default:
>          break;
>      }
> diff --git a/extras/mini-os/tpm_tis.c b/extras/mini-os/tpm_tis.c
> --- /dev/null
> +++ b/extras/mini-os/tpm_tis.c
> @@ -0,0 +1,1344 @@
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * This driver 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, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This driver is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Based upon the files:
> + *  drivers/char/tpm/tpm_tis.c
> + *  drivers/char/tpm/tpm.c
> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
> + */
> +#include <mini-os/ioremap.h>
> +#include <mini-os/iorw.h>
> +#include <mini-os/tpm_tis.h>
> +#include <mini-os/os.h>
> +#include <mini-os/sched.h>
> +#include <mini-os/byteorder.h>
> +#include <mini-os/events.h>
> +#include <mini-os/wait.h>
> +#include <mini-os/xmalloc.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +
> +#ifndef min
> +    #define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
> +#endif
> +
> +#define TPM_HEADER_SIZE 10
> +
> +#define TPM_BUFSIZE 2048
> +
> +struct tpm_input_header {
> +        uint16_t  tag;
> +        uint32_t  length;
> +        uint32_t  ordinal;
> +}__attribute__((packed));
> +
> +struct tpm_output_header {
> +        uint16_t  tag;
> +        uint32_t  length;
> +        uint32_t  return_code;
> +}__attribute__((packed));
> +
> +struct  stclear_flags_t {
> +        uint16_t  tag;
> +        uint8_t      deactivated;
> +        uint8_t      disableForceClear;
> +        uint8_t      physicalPresence;
> +        uint8_t      physicalPresenceLock;
> +        uint8_t      bGlobalLock;
> +}__attribute__((packed));
> +
> +struct  tpm_version_t {
> +        uint8_t      Major;
> +        uint8_t      Minor;
> +        uint8_t      revMajor;
> +        uint8_t      revMinor;
> +}__attribute__((packed));
> +
> +struct  tpm_version_1_2_t {
> +        uint16_t  tag;
> +        uint8_t      Major;
> +        uint8_t      Minor;
> +        uint8_t      revMajor;
> +        uint8_t      revMinor;
> +}__attribute__((packed));
> +
> +struct  timeout_t {
> +        uint32_t  a;
> +        uint32_t  b;
> +        uint32_t  c;
> +        uint32_t  d;
> +}__attribute__((packed));
> +
> +struct duration_t {
> +        uint32_t  tpm_short;
> +        uint32_t  tpm_medium;
> +        uint32_t  tpm_long;
> +}__attribute__((packed));
> +
> +struct permanent_flags_t {
> +        uint16_t  tag;
> +        uint8_t      disable;
> +        uint8_t      ownership;
> +        uint8_t      deactivated;
> +        uint8_t      readPubek;
> +        uint8_t      disableOwnerClear;
> +        uint8_t      allowMaintenance;
> +        uint8_t      physicalPresenceLifetimeLock;
> +        uint8_t      physicalPresenceHWEnable;
> +        uint8_t      physicalPresenceCMDEnable;
> +        uint8_t      CEKPUsed;
> +        uint8_t      TPMpost;
> +        uint8_t      TPMpostLock;
> +        uint8_t      FIPS;
> +        uint8_t      operator;
> +        uint8_t      enableRevokeEK;
> +        uint8_t      nvLocked;
> +        uint8_t      readSRKPub;
> +        uint8_t      tpmEstablished;
> +        uint8_t      maintenanceDone;
> +        uint8_t      disableFullDALogicInfo;
> +}__attribute__((packed));
> +
> +typedef union {
> +        struct  permanent_flags_t perm_flags;
> +        struct  stclear_flags_t stclear_flags;
> +        bool    owned;
> +        uint32_t  num_pcrs;
> +        struct  tpm_version_t   tpm_version;
> +        struct  tpm_version_1_2_t tpm_version_1_2;
> +        uint32_t  manufacturer_id;
> +        struct timeout_t  timeout;
> +        struct duration_t duration;
> +} cap_t;
> +
> +struct  tpm_getcap_params_in {
> +        uint32_t  cap;
> +        uint32_t  subcap_size;
> +        uint32_t  subcap;
> +}__attribute__((packed));
> +
> +struct  tpm_getcap_params_out {
> +        uint32_t  cap_size;
> +        cap_t   cap;
> +}__attribute__((packed));
> +
> +struct  tpm_readpubek_params_out {
> +        uint8_t      algorithm[4];
> +        uint8_t      encscheme[2];
> +        uint8_t      sigscheme[2];
> +        uint32_t  paramsize;
> +        uint8_t      parameters[12]; /*assuming RSA*/
> +        uint32_t  keysize;
> +        uint8_t      modulus[256];
> +        uint8_t      checksum[20];
> +}__attribute__((packed));
> +
> +typedef union {
> +        struct  tpm_input_header in;
> +        struct  tpm_output_header out;
> +} tpm_cmd_header;
> +
> +#define TPM_DIGEST_SIZE 20
> +struct tpm_pcrread_out {
> +        uint8_t      pcr_result[TPM_DIGEST_SIZE];
> +}__attribute__((packed));
> +
> +struct tpm_pcrread_in {
> +        uint32_t  pcr_idx;
> +}__attribute__((packed));
> +
> +struct tpm_pcrextend_in {
> +        uint32_t  pcr_idx;
> +        uint8_t      hash[TPM_DIGEST_SIZE];
> +}__attribute__((packed));
> +
> +typedef union {
> +        struct  tpm_getcap_params_out getcap_out;
> +        struct  tpm_readpubek_params_out readpubek_out;
> +        uint8_t      readpubek_out_buffer[sizeof(struct
> tpm_readpubek_params_out)];
> +        struct  tpm_getcap_params_in getcap_in;
> +        struct  tpm_pcrread_in  pcrread_in;
> +        struct  tpm_pcrread_out pcrread_out;
> +        struct  tpm_pcrextend_in pcrextend_in;
> +} tpm_cmd_params;
> +
> +struct tpm_cmd_t {
> +        tpm_cmd_header  header;
> +        tpm_cmd_params  params;
> +}__attribute__((packed));
> +
> +
> +enum tpm_duration {
> +   TPM_SHORT = 0,
> +   TPM_MEDIUM = 1,
> +   TPM_LONG = 2,
> +   TPM_UNDEFINED,
> +};
> +
> +#define TPM_MAX_ORDINAL 243
> +#define TPM_MAX_PROTECTED_ORDINAL 12
> +#define TPM_PROTECTED_ORDINAL_MASK 0xFF
> +
> +extern const uint8_t
> tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL];
> +extern const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL];
> +
> +#define TPM_DIGEST_SIZE 20
> +#define TPM_ERROR_SIZE 10
> +#define TPM_RET_CODE_IDX 6
> +
> +/* tpm_capabilities */
> +#define TPM_CAP_FLAG cpu_to_be32(4)
> +#define TPM_CAP_PROP cpu_to_be32(5)
> +#define CAP_VERSION_1_1 cpu_to_be32(0x06)
> +#define CAP_VERSION_1_2 cpu_to_be32(0x1A)
> +
> +/* tpm_sub_capabilities */
> +#define TPM_CAP_PROP_PCR cpu_to_be32(0x101)
> +#define TPM_CAP_PROP_MANUFACTURER cpu_to_be32(0x103)
> +#define TPM_CAP_FLAG_PERM cpu_to_be32(0x108)
> +#define TPM_CAP_FLAG_VOL cpu_to_be32(0x109)
> +#define TPM_CAP_PROP_OWNER cpu_to_be32(0x111)
> +#define TPM_CAP_PROP_TIS_TIMEOUT cpu_to_be32(0x115)
> +#define TPM_CAP_PROP_TIS_DURATION cpu_to_be32(0x120)
> +
> +
> +#define TPM_INTERNAL_RESULT_SIZE 200
> +#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
> +#define TPM_ORD_GET_CAP cpu_to_be32(101)
> +
> +extern const struct tpm_input_header tpm_getcap_header;
> +
> +
> +
> +const uint8_t tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
> +   TPM_UNDEFINED,          /* 0 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 5 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 10 */
> +   TPM_SHORT,
> +};
> +
> +const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
> +   TPM_UNDEFINED,          /* 0 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 5 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 10 */
> +   TPM_SHORT,
> +   TPM_MEDIUM,
> +   TPM_LONG,
> +   TPM_LONG,
> +   TPM_MEDIUM,             /* 15 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_MEDIUM,
> +   TPM_LONG,
> +   TPM_SHORT,              /* 20 */
> +   TPM_SHORT,
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_SHORT,              /* 25 */
> +   TPM_SHORT,
> +   TPM_MEDIUM,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_MEDIUM,             /* 30 */
> +   TPM_LONG,
> +   TPM_MEDIUM,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,              /* 35 */
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_MEDIUM,             /* 40 */
> +   TPM_LONG,
> +   TPM_MEDIUM,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,              /* 45 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_LONG,
> +   TPM_MEDIUM,             /* 50 */
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 55 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_MEDIUM,             /* 60 */
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_MEDIUM,             /* 65 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 70 */
> +   TPM_SHORT,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 75 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_LONG,               /* 80 */
> +   TPM_UNDEFINED,
> +   TPM_MEDIUM,
> +   TPM_LONG,
> +   TPM_SHORT,
> +   TPM_UNDEFINED,          /* 85 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 90 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_UNDEFINED,          /* 95 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_MEDIUM,             /* 100 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 105 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 110 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,              /* 115 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_LONG,               /* 120 */
> +   TPM_LONG,
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,
> +   TPM_SHORT,              /* 125 */
> +   TPM_SHORT,
> +   TPM_LONG,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,              /* 130 */
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,          /* 135 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 140 */
> +   TPM_SHORT,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 145 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 150 */
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_UNDEFINED,          /* 155 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 160 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 165 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_LONG,               /* 170 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 175 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_MEDIUM,             /* 180 */
> +   TPM_SHORT,
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,             /* 185 */
> +   TPM_SHORT,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 190 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 195 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 200 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,
> +   TPM_SHORT,              /* 205 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_MEDIUM,             /* 210 */
> +   TPM_UNDEFINED,
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,          /* 215 */
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,
> +   TPM_SHORT,              /* 220 */
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_SHORT,
> +   TPM_UNDEFINED,          /* 225 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 230 */
> +   TPM_LONG,
> +   TPM_MEDIUM,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,          /* 235 */
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_UNDEFINED,
> +   TPM_SHORT,              /* 240 */
> +   TPM_UNDEFINED,
> +   TPM_MEDIUM,
> +};
> +
> +const struct tpm_input_header tpm_getcap_header = {
> +        .tag = TPM_TAG_RQU_COMMAND,
> +        .length = cpu_to_be32(22),
> +        .ordinal = TPM_ORD_GET_CAP
> +};
> +
> +
> +enum tis_access {
> +   TPM_ACCESS_VALID = 0x80,
> +   TPM_ACCESS_ACTIVE_LOCALITY = 0x20,    /* (R) */
> +   TPM_ACCESS_RELINQUISH_LOCALITY = 0x20,/* (W) */
> +   TPM_ACCESS_REQUEST_PENDING = 0x04,    /* (W) */
> +   TPM_ACCESS_REQUEST_USE = 0x02,    /* (W) */
> +};
> +
> +enum tis_status {
> +   TPM_STS_VALID = 0x80,        /* (R) */
> +   TPM_STS_COMMAND_READY = 0x40,    /* (R) */
> +   TPM_STS_DATA_AVAIL = 0x10,        /* (R) */
> +   TPM_STS_DATA_EXPECT = 0x08,        /* (R) */
> +   TPM_STS_GO = 0x20,            /* (W) */
> +};
> +
> +enum tis_int_flags {
> +   TPM_GLOBAL_INT_ENABLE = 0x80000000,
> +   TPM_INTF_BURST_COUNT_STATIC = 0x100,
> +   TPM_INTF_CMD_READY_INT = 0x080,
> +   TPM_INTF_INT_EDGE_FALLING = 0x040,
> +   TPM_INTF_INT_EDGE_RISING = 0x020,
> +   TPM_INTF_INT_LEVEL_LOW = 0x010,
> +   TPM_INTF_INT_LEVEL_HIGH = 0x008,
> +   TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
> +   TPM_INTF_STS_VALID_INT = 0x002,
> +   TPM_INTF_DATA_AVAIL_INT = 0x001,
> +};
> +
> +enum tis_defaults {
> +   TIS_MEM_BASE = 0xFED40000,
> +   TIS_MEM_LEN  = 0x5000,
> +   TIS_SHORT_TIMEOUT = 750, /*ms*/
> +   TIS_LONG_TIMEOUT = 2000, /*2 sec */
> +};
> +
> +#define TPM_TIMEOUT 5
> +
> +#define TPM_ACCESS(t, l)                   (((uint8_t*)t->pages[l]) +
> 0x0000)
> +#define TPM_INT_ENABLE(t, l)
> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0008))
> +#define TPM_INT_VECTOR(t, l)               (((uint8_t*)t->pages[l]) +
> 0x000C)
> +#define TPM_INT_STATUS(t, l)               (((uint8_t*)t->pages[l]) +
> 0x0010)
> +#define TPM_INTF_CAPS(t, l)
> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0014))
> +#define TPM_STS(t, l)
> ((uint8_t*)(((uint8_t*)t->pages[l]) + 0x0018))
> +#define TPM_DATA_FIFO(t, l)                (((uint8_t*)t->pages[l]) +
> 0x0024)
> +
> +#define TPM_DID_VID(t, l)
> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0F00))
> +#define TPM_RID(t, l)                      (((uint8_t*)t->pages[l]) +
> 0x0F04)
> +
> +struct tpm_chip {
> +   int enabled_localities;
> +   int locality;
> +   unsigned long baseaddr;
> +   uint8_t* pages[5];
> +   int did, vid, rid;
> +
> +   uint8_t data_buffer[TPM_BUFSIZE];
> +   int data_len;
> +
> +   s_time_t timeout_a, timeout_b, timeout_c, timeout_d;
> +   s_time_t duration[3];
> +
> +#ifdef HAVE_LIBC
> +   int fd;
> +#endif
> +
> +   unsigned int irq;
> +   struct wait_queue_head read_queue;
> +   struct wait_queue_head int_queue;
> +};
> +
> +
> +static void __init_tpm_chip(struct tpm_chip* tpm) {
> +   tpm->enabled_localities = TPM_TIS_EN_LOCLALL;
> +   tpm->locality = -1;
> +   tpm->baseaddr = 0;
> +   tpm->pages[0] = tpm->pages[1] = tpm->pages[2] = tpm->pages[3] =
> tpm->pages[4] = NULL;
> +   tpm->vid = 0;
> +   tpm->did = 0;
> +   tpm->irq = 0;
> +   init_waitqueue_head(&tpm->read_queue);
> +   init_waitqueue_head(&tpm->int_queue);
> +
> +   tpm->data_len = -1;
> +
> +#ifdef HAVE_LIBC
> +   tpm->fd = -1;
> +#endif
> +}
> +
> +/*
> + * Returns max number of nsecs to wait
> + */
> +s_time_t tpm_calc_ordinal_duration(struct tpm_chip *chip,
> +      uint32_t ordinal)
> +{
> +   int duration_idx = TPM_UNDEFINED;
> +   s_time_t duration = 0;
> +
> +   if (ordinal < TPM_MAX_ORDINAL)
> +      duration_idx = tpm_ordinal_duration[ordinal];
> +   else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
> +     TPM_MAX_PROTECTED_ORDINAL)
> +      duration_idx =
> +     tpm_protected_ordinal_duration[ordinal &
> +     TPM_PROTECTED_ORDINAL_MASK];
> +
> +   if (duration_idx != TPM_UNDEFINED) {
> +      duration = chip->duration[duration_idx];
> +   }
> +
> +   if (duration <= 0) {
> +      return SECONDS(120);
> +   }
> +   else
> +   {
> +      return duration;
> +   }
> +}
> +
> +
> +static int locality_enabled(struct tpm_chip* tpm, int l) {
> +   return tpm->enabled_localities & (1 << l);
> +}
> +
> +static int check_locality(struct tpm_chip* tpm, int l) {
> +   if(locality_enabled(tpm, l) && (ioread8(TPM_ACCESS(tpm, l)) &
> +        (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
> +     (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
> +      return l;
> +   }
> +   return -1;
> +}
> +
> +void release_locality(struct tpm_chip* tpm, int l, int force)
> +{
> +   if (locality_enabled(tpm, l) && (force || (ioread8(TPM_ACCESS(tpm, l)) &
> +           (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
> +        (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))) {
> +      iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_RELINQUISH_LOCALITY);
> +   }
> +}
> +
> +int tpm_tis_request_locality(struct tpm_chip* tpm, int l) {
> +
> +   s_time_t stop;
> +   /*Make sure locality is valid */
> +   if(!locality_enabled(tpm, l)) {
> +      printk("tpm_tis_change_locality() Tried to change to locality %d,
> but it is disabled or invalid!\n", l);
> +      return -1;
> +   }
> +   /* Check if we already have the current locality */
> +   if(check_locality(tpm, l) >= 0) {
> +      return tpm->locality = l;
> +   }
> +   /* Set the new locality*/
> +   iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_REQUEST_USE);
> +
> +   if(tpm->irq) {
> +      /* Wait for interrupt */
> +      wait_event_deadline(tpm->int_queue, (check_locality(tpm, l) >=
> 0), NOW() + tpm->timeout_a);
> +
> +      /* FIXME: Handle timeout event, should return error in that case */
> +      return l;
> +   } else {
> +      /* Wait for burstcount */
> +      stop = NOW() + tpm->timeout_a;
> +      do {
> +     if(check_locality(tpm, l) >= 0) {
> +        return tpm->locality = l;
> +     }
> +     msleep(TPM_TIMEOUT);
> +      } while(NOW() < stop);
> +   }
> +
> +   printk("REQ LOCALITY FAILURE\n");
> +   return -1;
> +}
> +
> +static uint8_t tpm_tis_status(struct tpm_chip* tpm) {
> +   return ioread8(TPM_STS(tpm, tpm->locality));
> +}
> +
> +/* This causes the current command to be aborted */
> +static void tpm_tis_ready(struct tpm_chip* tpm) {
> +   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_COMMAND_READY);
> +}
> +#define tpm_tis_cancel_cmd(v) tpm_tis_ready(v)
> +
> +static int get_burstcount(struct tpm_chip* tpm) {
> +   s_time_t stop;
> +   int burstcnt;
> +
> +   stop = NOW() + tpm->timeout_d;
> +   do {
> +      burstcnt = ioread8((TPM_STS(tpm, tpm->locality) + 1));
> +      burstcnt += ioread8(TPM_STS(tpm, tpm->locality) + 2) << 8;
> +
> +      if (burstcnt) {
> +     return burstcnt;
> +      }
> +      msleep(TPM_TIMEOUT);
> +   } while(NOW() < stop);
> +   return -EBUSY;
> +}
> +
> +static int wait_for_stat(struct tpm_chip* tpm, uint8_t mask,
> +      unsigned long timeout, struct wait_queue_head* queue) {
> +   s_time_t stop;
> +   uint8_t status;
> +
> +   status = tpm_tis_status(tpm);
> +   if((status & mask) == mask) {
> +      return 0;
> +   }
> +
> +   if(tpm->irq) {
> +      wait_event_deadline(*queue, ((tpm_tis_status(tpm) & mask) ==
> mask), timeout);
> +      /* FIXME: Check for timeout and return -ETIME */
> +      return 0;
> +   } else {
> +      stop = NOW() + timeout;
> +      do {
> +     msleep(TPM_TIMEOUT);
> +     status = tpm_tis_status(tpm);
> +     if((status & mask) == mask)
> +        return 0;
> +      } while( NOW() < stop);
> +   }
> +   return -ETIME;
> +}
> +
> +static int recv_data(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
> +   int size = 0;
> +   int burstcnt;
> +   while( size < count &&
> +     wait_for_stat(tpm,
> +        TPM_STS_DATA_AVAIL | TPM_STS_VALID,
> +        tpm->timeout_c,
> +        &tpm->read_queue)
> +     == 0) {
> +      burstcnt = get_burstcount(tpm);
> +      for(; burstcnt > 0 && size < count; --burstcnt)
> +      {
> +     buf[size++] = ioread8(TPM_DATA_FIFO(tpm, tpm->locality));
> +      }
> +   }
> +   return size;
> +}
> +
> +int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
> +   int size = 0;
> +   int expected, status;
> +
> +   if (count < TPM_HEADER_SIZE) {
> +      size = -EIO;
> +      goto out;
> +   }
> +
> +   /* read first 10 bytes, including tag, paramsize, and result */
> +   if((size =
> +        recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
> +      printk("Error reading tpm cmd header\n");
> +      goto out;
> +   }
> +
> +   expected = be32_to_cpu(*((uint32_t*)(buf + 2)));
> +   if(expected > count) {
> +      size = -EIO;
> +      goto out;
> +   }
> +
> +   if((size += recv_data(tpm, & buf[TPM_HEADER_SIZE],
> +           expected - TPM_HEADER_SIZE)) < expected) {
> +      printk("Unable to read rest of tpm command size=%d
> expected=%d\n", size, expected);
> +      size = -ETIME;
> +      goto out;
> +   }
> +
> +   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
> +   status = tpm_tis_status(tpm);
> +   if(status & TPM_STS_DATA_AVAIL) {
> +      printk("Error: left over data\n");
> +      size = -EIO;
> +      goto out;
> +   }
> +
> +out:
> +   tpm_tis_ready(tpm);
> +   release_locality(tpm, tpm->locality, 0);
> +   return size;
> +}
> +int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) {
> +   int rc;
> +   int status, burstcnt = 0;
> +   int count = 0;
> +   uint32_t ordinal;
> +
> +   if(tpm_tis_request_locality(tpm, tpm->locality) < 0) {
> +      return -EBUSY;
> +   }
> +
> +   status = tpm_tis_status(tpm);
> +   if((status & TPM_STS_COMMAND_READY) == 0) {
> +      tpm_tis_ready(tpm);
> +      if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b,
> &tpm->int_queue) < 0) {
> +     rc = -ETIME;
> +     goto out_err;
> +      }
> +   }
> +
> +   while(count < len - 1) {
> +      burstcnt = get_burstcount(tpm);
> +      for(;burstcnt > 0 && count < len -1; --burstcnt) {
> +     iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]);
> +      }
> +
> +      wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
> +      status = tpm_tis_status(tpm);
> +      if((status & TPM_STS_DATA_EXPECT) == 0) {
> +     rc = -EIO;
> +     goto out_err;
> +      }
> +   }
> +
> +   /*Write last byte*/
> +   iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]);
> +   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue);
> +   status = tpm_tis_status(tpm);
> +   if((status & TPM_STS_DATA_EXPECT) != 0) {
> +      rc = -EIO;
> +      goto out_err;
> +   }
> +
> +   /*go and do it*/
> +   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO);
> +
> +   if(tpm->irq) {
> +      /*Wait for interrupt */
> +      ordinal = be32_to_cpu(*(buf + 6));
> +      if(wait_for_stat(tpm,
> +           TPM_STS_DATA_AVAIL | TPM_STS_VALID,
> +           tpm_calc_ordinal_duration(tpm, ordinal),
> +           &tpm->read_queue) < 0) {
> +     rc = -ETIME;
> +     goto out_err;
> +      }
> +   }
> +#ifdef HAVE_LIBC
> +   if(tpm->fd >= 0) {
> +      files[tpm->fd].read = 0;
> +      files[tpm->fd].tpm_tis.respgot = 0;
> +      files[tpm->fd].tpm_tis.offset = 0;
> +   }
> +#endif
> +   return len;
> +
> +out_err:
> +   tpm_tis_ready(tpm);
> +   release_locality(tpm, tpm->locality, 0);
> +   return rc;
> +}
> +
> +static void tpm_tis_irq_handler(evtchn_port_t port, struct pt_regs
> *regs, void* data)
> +{
> +   struct tpm_chip* tpm = data;
> +   uint32_t interrupt;
> +   int i;
> +
> +   interrupt = ioread32(TPM_INT_STATUS(tpm, tpm->locality));
> +   if(interrupt == 0) {
> +      return;
> +   }
> +
> +   if(interrupt & TPM_INTF_DATA_AVAIL_INT) {
> +      wake_up(&tpm->read_queue);
> +   }
> +   if(interrupt & TPM_INTF_LOCALITY_CHANGE_INT) {
> +      for(i = 0; i < 5; ++i) {
> +     if(check_locality(tpm, i) >= 0) {
> +        break;
> +     }
> +      }
> +   }
> +   if(interrupt & (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
> +        TPM_INTF_CMD_READY_INT)) {
> +      wake_up(&tpm->int_queue);
> +   }
> +
> +   /* Clear interrupts handled with TPM_EOI */
> +   iowrite32(TPM_INT_STATUS(tpm, tpm->locality), interrupt);
> +   ioread32(TPM_INT_STATUS(tpm, tpm->locality));
> +   return;
> +}
> +
> +/*
> + * Internal kernel interface to transmit TPM commands
> + */
> +static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf,
> +      size_t bufsiz)
> +{
> +   ssize_t rc;
> +   uint32_t count, ordinal;
> +   s_time_t stop;
> +
> +   count = be32_to_cpu(*((uint32_t *) (buf + 2)));
> +   ordinal = be32_to_cpu(*((uint32_t *) (buf + 6)));
> +   if (count == 0)
> +      return -ENODATA;
> +   if (count > bufsiz) {
> +      printk("Error: invalid count value %x %zx \n", count, bufsiz);
> +      return -E2BIG;
> +   }
> +
> +   //down(&chip->tpm_mutex);
> +
> +   if ((rc = tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) {
> +      printk("tpm_transmit: tpm_send: error %zd\n", rc);
> +      goto out;
> +   }
> +
> +   if (chip->irq)
> +      goto out_recv;
> +
> +   stop = NOW() + tpm_calc_ordinal_duration(chip, ordinal);
> +   do {
> +      uint8_t status = tpm_tis_status(chip);
> +      if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) ==
> +        (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
> +     goto out_recv;
> +
> +      if ((status == TPM_STS_COMMAND_READY)) {
> +     printk("TPM Error: Operation Canceled\n");
> +     rc = -ECANCELED;
> +     goto out;
> +      }
> +
> +      msleep(TPM_TIMEOUT);    /* CHECK */
> +      rmb();
> +   } while (NOW() < stop);
> +
> +   /* Cancel the command */
> +   tpm_tis_cancel_cmd(chip);
> +   printk("TPM Operation Timed out\n");
> +   rc = -ETIME;
> +   goto out;
> +
> +out_recv:
> +   if((rc = tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) {
> +      printk("tpm_transmit: tpm_recv: error %d\n", rc);
> +   }
> +out:
> +   //up(&chip->tpm_mutex);
> +   return rc;
> +}
> +
> +static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
> +                            int len, const char *desc)
> +{
> +        int err;
> +
> +        len = tpm_transmit(chip,(uint8_t *) cmd, len);
> +        if (len <  0)
> +                return len;
> +        if (len == TPM_ERROR_SIZE) {
> +                err = be32_to_cpu(cmd->header.out.return_code);
> +                printk("A TPM error (%d) occurred %s\n", err, desc);
> +                return err;
> +        }
> +        return 0;
> +}
> +
> +void tpm_get_timeouts(struct tpm_chip *chip)
> +{
> +   struct tpm_cmd_t tpm_cmd;
> +   struct timeout_t *timeout_cap;
> +   struct duration_t *duration_cap;
> +   ssize_t rc;
> +   uint32_t timeout;
> +
> +   tpm_cmd.header.in = tpm_getcap_header;
> +   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
> +   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> +   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> +
> +   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> +     "attempting to determine the timeouts")) != 0) {
> +      printk("transmit failed %d\n", rc);
> +      goto duration;
> +   }
> +
> +   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
> +     != 4 * sizeof(uint32_t)) {
> +      printk("Out len check failure %lu \n",
> be32_to_cpu(tpm_cmd.header.out.length));
> +      goto duration;
> +   }
> +
> +   timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
> +   /* Don't overwrite default if value is 0 */
> +   timeout = be32_to_cpu(timeout_cap->a);
> +   if (timeout)
> +      chip->timeout_a = MICROSECS(timeout); /*Convert to msec */
> +   timeout = be32_to_cpu(timeout_cap->b);
> +   if (timeout)
> +      chip->timeout_b = MICROSECS(timeout); /*Convert to msec */
> +   timeout = be32_to_cpu(timeout_cap->c);
> +   if (timeout)
> +      chip->timeout_c = MICROSECS(timeout); /*Convert to msec */
> +   timeout = be32_to_cpu(timeout_cap->d);
> +   if (timeout)
> +      chip->timeout_d = MICROSECS(timeout); /*Convert to msec */
> +
> +duration:
> +   tpm_cmd.header.in = tpm_getcap_header;
> +   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
> +   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> +   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
> +
> +   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> +     "attempting to determine the durations")) < 0) {
> +      return;
> +   }
> +
> +   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
> +     != 3 * sizeof(uint32_t)) {
> +      return;
> +   }
> +        duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
> +        chip->duration[TPM_SHORT] = be32_to_cpu(duration_cap->tpm_short);
> +        /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets
> the above
> +         * value wrong and apparently reports msecs rather than usecs.
> So we
> +         * fix up the resulting too-small TPM_SHORT value to make
> things work.
> +         */
> +        if (chip->duration[TPM_SHORT] < 10) {
> +       chip->duration[TPM_SHORT] = MILLISECS(chip->duration[TPM_SHORT]);
> +    } else {
> +       chip->duration[TPM_SHORT] = MICROSECS(chip->duration[TPM_SHORT]);
> +    }
> +
> +        chip->duration[TPM_MEDIUM] =
> MICROSECS(be32_to_cpu(duration_cap->tpm_medium));
> +        chip->duration[TPM_LONG] =
> MICROSECS(be32_to_cpu(duration_cap->tpm_long));
> +}
> +
> +
> +
> +void tpm_continue_selftest(struct tpm_chip* chip) {
> +   uint8_t data[] = {
> +      0, 193,                 /* TPM_TAG_RQU_COMMAND */
> +      0, 0, 0, 10,            /* length */
> +      0, 0, 0, 83,            /* TPM_ORD_GetCapability */
> +   };
> +
> +   tpm_transmit(chip, data, sizeof(data));
> +}
> +
> +ssize_t tpm_getcap(struct tpm_chip *chip, uint32_t subcap_id, cap_t *cap,
> +                   const char *desc)
> +{
> +        struct tpm_cmd_t tpm_cmd;
> +        int rc;
> +
> +        tpm_cmd.header.in = tpm_getcap_header;
> +        if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
> +                tpm_cmd.params.getcap_in.cap = subcap_id;
> +                /*subcap field not necessary */
> +                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
> +                tpm_cmd.header.in.length -= cpu_to_be32(sizeof(uint32_t));
> +        } else {
> +                if (subcap_id == TPM_CAP_FLAG_PERM ||
> +                    subcap_id == TPM_CAP_FLAG_VOL)
> +                        tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
> +                else
> +                        tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
> +                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> +                tpm_cmd.params.getcap_in.subcap = subcap_id;
> +        }
> +        rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
> +        if (!rc)
> +                *cap = tpm_cmd.params.getcap_out.cap;
> +        return rc;
> +}
> +
> +
> +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
> unsigned int irq)
> +{
> +   int i;
> +   unsigned long addr;
> +   struct tpm_chip* tpm = NULL;
> +   uint32_t didvid;
> +   uint32_t intfcaps;
> +   uint32_t intmask;
> +
> +   printk("============= Init TPM TIS Driver ==============\n");
> +
> +   /*Sanity check the localities input */
> +   if(localities & ~TPM_TIS_EN_LOCLALL) {
> +      printk("init_tpm_tis() Invalid locality specification! %X\n",
> localities);
> +      goto abort_egress;
> +   }
> +
> +   printk("IOMEM Machine Base Address: %lX\n", baseaddr);
> +
> +   /* Create the tpm data structure */
> +   tpm = malloc(sizeof(struct tpm_chip));
> +   __init_tpm_chip(tpm);
> +
> +   /* Set the enabled localities - if 0 we leave default as all enabled */
> +   if(localities != 0) {
> +      tpm->enabled_localities = localities;
> +   }
> +   printk("Enabled Localities: ");
> +   for(i = 0; i < 5; ++i) {
> +      if(locality_enabled(tpm, i)) {
> +     printk("%d ", i);
> +      }
> +   }
> +   printk("\n");
> +
> +   /* Set the base machine address */
> +   tpm->baseaddr = baseaddr;
> +
> +   /* Set default timeouts */
> +   tpm->timeout_a = MILLISECS(TIS_SHORT_TIMEOUT);
> +   tpm->timeout_b = MILLISECS(TIS_LONG_TIMEOUT);
> +   tpm->timeout_c = MILLISECS(TIS_SHORT_TIMEOUT);
> +   tpm->timeout_d = MILLISECS(TIS_SHORT_TIMEOUT);
> +
> +   /*Map the mmio pages */
> +   addr = tpm->baseaddr;
> +   for(i = 0; i < 5; ++i) {
> +      if(locality_enabled(tpm, i)) {
> +     /* Map the page in now */
> +     if((tpm->pages[i] = ioremap_nocache(addr, PAGE_SIZE)) == NULL) {
> +        printk("Unable to map iomem page a address %p\n", addr);
> +        goto abort_egress;
> +     }
> +
> +     /* Set default locality to the first enabled one */
> +     if (tpm->locality < 0) {
> +        if(tpm_tis_request_locality(tpm, i) < 0) {
> +           printk("Unable to request locality %d??\n", i);
> +           goto abort_egress;
> +        }
> +     }
> +      }
> +      addr += PAGE_SIZE;
> +   }
> +
> +
> +   /* Get the vendor and device ids */
> +   didvid = ioread32(TPM_DID_VID(tpm, tpm->locality));
> +   tpm->did = didvid >> 16;
> +   tpm->vid = didvid & 0xFFFF;
> +
> +
> +   /* Get the revision id */
> +   tpm->rid = ioread8(TPM_RID(tpm, tpm->locality));
> +
> +   printk("1.2 TPM (device-id=0x%X vendor-id = %X rev-id = %X)\n",
> tpm->did, tpm->vid, tpm->rid);
> +
> +   intfcaps = ioread32(TPM_INTF_CAPS(tpm, tpm->locality));
> +   printk("TPM interface capabilities (0x%x):\n", intfcaps);
> +   if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
> +      printk("\tBurst Count Static\n");
> +   if (intfcaps & TPM_INTF_CMD_READY_INT)
> +      printk("\tCommand Ready Int Support\n");
> +   if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
> +      printk("\tInterrupt Edge Falling\n");
> +   if (intfcaps & TPM_INTF_INT_EDGE_RISING)
> +      printk("\tInterrupt Edge Rising\n");
> +   if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
> +      printk("\tInterrupt Level Low\n");
> +   if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
> +      printk("\tInterrupt Level High\n");
> +   if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
> +      printk("\tLocality Change Int Support\n");
> +   if (intfcaps & TPM_INTF_STS_VALID_INT)
> +      printk("\tSts Valid Int Support\n");
> +   if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
> +      printk("\tData Avail Int Support\n");
> +
> +   /*Interupt setup */
> +   intmask = ioread32(TPM_INT_ENABLE(tpm, tpm->locality));
> +
> +   intmask |= TPM_INTF_CMD_READY_INT
> +      | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
> +      | TPM_INTF_STS_VALID_INT;
> +
> +   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask);
> +
> +   /*If interupts are enabled, handle it */
> +   if(irq) {
> +      if(irq != TPM_PROBE_IRQ) {
> +     tpm->irq = irq;
> +      } else {
> +     /*FIXME add irq probing feature later */
> +     printk("IRQ probing not implemented\n");
> +      }
> +   }
> +
> +   if(tpm->irq) {
> +      iowrite8(TPM_INT_VECTOR(tpm, tpm->locality), tpm->irq);
> +
> +      if(bind_pirq(tpm->irq, 1, tpm_tis_irq_handler, tpm) != 0) {
> +     printk("Unabled to request irq: %u for use\n", tpm->irq);
> +     printk("Will use polling mode\n");
> +     tpm->irq = 0;
> +      } else {
> +     /* Clear all existing */
> +     iowrite32(TPM_INT_STATUS(tpm, tpm->locality),
> ioread32(TPM_INT_STATUS(tpm, tpm->locality)));
> +
> +     /* Turn on interrupts */
> +     iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask |
> TPM_GLOBAL_INT_ENABLE);
> +      }
> +   }
> +
> +   tpm_get_timeouts(tpm);
> +   tpm_continue_selftest(tpm);
> +
> +
> +   return tpm;
> +abort_egress:
> +   if(tpm != NULL) {
> +      shutdown_tpm_tis(tpm);
> +   }
> +   return NULL;
> +}
> +
> +void shutdown_tpm_tis(struct tpm_chip* tpm){
> +   int i;
> +
> +   printk("Shutting down tpm_tis device\n");
> +
> +   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), ~TPM_GLOBAL_INT_ENABLE);
> +
> +   /*Unmap all of the mmio pages */
> +   for(i = 0; i < 5; ++i) {
> +      if(tpm->pages[i] != NULL) {
> +     iounmap(tpm->pages[i], PAGE_SIZE);
> +     tpm->pages[i] = NULL;
> +      }
> +   }
> +   free(tpm);
> +   return;
> +}
> +
> +
> +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
> uint8_t** resp, size_t* resplen)
> +{
> +   if(tpm->locality < 0) {
> +      printk("tpm_tis_cmd() failed! locality not set!\n");
> +      return -1;
> +   }
> +   if(reqlen > TPM_BUFSIZE) {
> +      reqlen = TPM_BUFSIZE;
> +   }
> +   memcpy(tpm->data_buffer, req, reqlen);
> +   *resplen = tpm_transmit(tpm, tpm->data_buffer, TPM_BUFSIZE);
> +
> +   *resp = malloc(*resplen);
> +   memcpy(*resp, tpm->data_buffer, *resplen);
> +   return 0;
> +}
> +
> +#ifdef HAVE_LIBC
> +int tpm_tis_open(struct tpm_chip* tpm)
> +{
> +   /* Silently prevent multiple opens */
> +   if(tpm->fd != -1) {
> +      return tpm->fd;
> +   }
> +
> +   tpm->fd = alloc_fd(FTYPE_TPM_TIS);
> +   printk("tpm_tis_open() -> %d\n", tpm->fd);
> +   files[tpm->fd].tpm_tis.dev = tpm;
> +   files[tpm->fd].tpm_tis.offset = 0;
> +   files[tpm->fd].tpm_tis.respgot = 0;
> +   return tpm->fd;
> +}
> +
> +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count)
> +{
> +   struct tpm_chip* tpm;
> +   tpm = files[fd].tpm_tis.dev;
> +
> +   if(tpm->locality < 0) {
> +      printk("tpm_tis_posix_write() failed! locality not set!\n");
> +      errno = EINPROGRESS;
> +      return -1;
> +   }
> +   if(count == 0) {
> +      return 0;
> +   }
> +
> +   /* Return an error if we are already processing a command */
> +   if(count > TPM_BUFSIZE) {
> +      count = TPM_BUFSIZE;
> +   }
> +   /* Send the command now */
> +   memcpy(tpm->data_buffer, buf, count);
> +   if((tpm->data_len = tpm_transmit(tpm, tpm->data_buffer,
> TPM_BUFSIZE)) < 0) {
> +      errno = EIO;
> +      return -1;
> +   }
> +   return count;
> +}
> +
> +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count)
> +{
> +   int rc;
> +   struct tpm_chip* tpm;
> +   tpm = files[fd].tpm_tis.dev;
> +
> +   if(count == 0) {
> +      return 0;
> +   }
> +
> +   /* If there is no tpm resp to read, return EIO */
> +   if(tpm->data_len < 0) {
> +      errno = EIO;
> +      return -1;
> +   }
> +
> +
> +   /* Handle EOF case */
> +   if(files[fd].tpm_tis.offset >= tpm->data_len) {
> +      rc = 0;
> +   } else {
> +      rc = min(tpm->data_len - files[fd].tpm_tis.offset, count);
> +      memcpy(buf, tpm->data_buffer + files[fd].tpm_tis.offset, rc);
> +   }
> +   files[fd].tpm_tis.offset += rc;
> +   /* Reset the data pending flag */
> +   return rc;
> +}
> +int tpm_tis_posix_fstat(int fd, struct stat* buf)
> +{
> +   struct tpm_chip* tpm;
> +   tpm = files[fd].tpm_tis.dev;
> +
> +   buf->st_mode = O_RDWR;
> +   buf->st_uid = 0;
> +   buf->st_gid = 0;
> +   buf->st_size = be32_to_cpu(*((uint32_t*)(tpm->data_buffer + 2)));
> +   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
> +   return 0;
> +}
> +
> +
> +#endif
> diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c
> --- /dev/null
> +++ b/extras/mini-os/tpmback.c
> @@ -0,0 +1,1114 @@
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * This driver 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, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This driver is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Based upon the files:
> + *  drivers/xen/tpmbk.c
> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
> + */
> +#include <mini-os/os.h>
> +#include <mini-os/xenbus.h>
> +#include <mini-os/events.h>
> +#include <errno.h>
> +#include <mini-os/gnttab.h>
> +#include <xen/io/xenbus.h>
> +#include <xen/io/tpmif.h>
> +#include <xen/io/protocols.h>
> +#include <mini-os/xmalloc.h>
> +#include <time.h>
> +#include <mini-os/tpmback.h>
> +#include <mini-os/lib.h>
> +#include <fcntl.h>
> +#include <mini-os/mm.h>
> +#include <mini-os/posix/sys/mman.h>
> +#include <mini-os/semaphore.h>
> +#include <mini-os/wait.h>
> +
> +
> +#ifndef HAVE_LIBC
> +#define strtoul simple_strtoul
> +#endif
> +
> +//#define TPMBACK_PRINT_DEBUG
> +#ifdef TPMBACK_PRINT_DEBUG
> +#define TPMBACK_DEBUG(fmt,...) printk("Tpmback:Debug("__FILE__":%d) "
> fmt, __LINE__, ##__VA_ARGS__)
> +#define TPMBACK_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
> +#else
> +#define TPMBACK_DEBUG(fmt,...)
> +#endif
> +#define TPMBACK_ERR(fmt,...) printk("Tpmback:Error " fmt, ##__VA_ARGS__)
> +#define TPMBACK_LOG(fmt,...) printk("Tpmback:Info " fmt, ##__VA_ARGS__)
> +
> +#define min(a,b) (((a) < (b)) ? (a) : (b))
> +
> +/* Default size of the tpmif array at initialization */
> +#define DEF_ARRAY_SIZE 1
> +
> +/* tpmif and tpmdev flags */
> +#define TPMIF_CLOSED 1
> +#define TPMIF_REQ_READY 2
> +
> +struct tpmif {
> +   domid_t domid;
> +   unsigned int handle;
> +
> +   char* fe_path;
> +   char* fe_state_path;
> +
> +   /* Locally bound event channel*/
> +   evtchn_port_t evtchn;
> +
> +   /* Shared page */
> +   tpmif_tx_interface_t* tx;
> +
> +   /* pointer to TPMIF_RX_RING_SIZE pages */
> +   void** pages;
> +
> +   enum xenbus_state state;
> +   enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
> +
> +   char* uuid;
> +
> +   /* state flags */
> +   int flags;
> +};
> +typedef struct tpmif tpmif_t;
> +
> +struct tpmback_dev {
> +
> +   tpmif_t** tpmlist;
> +   unsigned long num_tpms;
> +   unsigned long num_alloc;
> +
> +   struct gntmap map;
> +
> +   /* True if at least one tpmif has a request to be handled */
> +   int flags;
> +
> +   /* exclusive domains, see init_tpmback comment in tpmback.h */
> +   char** exclusive_uuids;
> +
> +   xenbus_event_queue events;
> +
> +   /* Callbacks */
> +   void (*open_callback)(domid_t, unsigned int);
> +   void (*close_callback)(domid_t, unsigned int);
> +   void (*suspend_callback)(domid_t, unsigned int);
> +   void (*resume_callback)(domid_t, unsigned int);
> +};
> +typedef struct tpmback_dev tpmback_dev_t;
> +
> +enum { EV_NONE, EV_NEWFE, EV_STCHNG } tpm_ev_enum;
> +
> +/* Global objects */
> +static struct thread* eventthread = NULL;
> +static tpmback_dev_t gtpmdev = {
> +   .tpmlist = NULL,
> +   .num_tpms = 0,
> +   .num_alloc = 0,
> +   .flags = TPMIF_CLOSED,
> +   .events = NULL,
> +   .open_callback = NULL,
> +   .close_callback = NULL,
> +   .suspend_callback = NULL,
> +   .resume_callback = NULL,
> +};
> +struct wait_queue_head waitq;
> +int globalinit = 0;
> +
> +/************************************
> + * TPMIF SORTED ARRAY FUNCTIONS
> + * tpmback_dev_t.tpmlist is a sorted array, sorted by domid and then
> handle number
> + * Duplicates are not allowed
> + * **********************************/
> +
> +inline void tpmif_req_ready(tpmif_t* tpmif) {
> +   tpmif->flags |= TPMIF_REQ_READY;
> +   gtpmdev.flags |= TPMIF_REQ_READY;
> +}
> +
> +inline void tpmdev_check_req(void) {
> +   int i;
> +   int flags;
> +   local_irq_save(flags);
> +   for(i = 0; i < gtpmdev.num_tpms; ++i) {
> +      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
> +     gtpmdev.flags |= TPMIF_REQ_READY;
> +     local_irq_restore(flags);
> +     return;
> +      }
> +   }
> +   gtpmdev.flags &= ~TPMIF_REQ_READY;
> +   local_irq_restore(flags);
> +}
> +
> +inline void tpmif_req_finished(tpmif_t* tpmif) {
> +   tpmif->flags &= ~TPMIF_REQ_READY;
> +   tpmdev_check_req();
> +}
> +
> +int __get_tpmif_index(int st, int n, domid_t domid, unsigned int handle)
> +{
> +   int i = st + n /2;
> +   tpmif_t* tmp;
> +
> +   if( n <= 0 )
> +      return -1;
> +
> +   tmp = gtpmdev.tpmlist[i];
> +   if(domid == tmp->domid && tmp->handle == handle) {
> +      return i;
> +   } else if ( (domid < tmp->domid) ||
> +     (domid == tmp->domid && handle < tmp->handle)) {
> +      return __get_tpmif_index(st, n/2, domid, handle);
> +   } else {
> +      return __get_tpmif_index(i + 1, n/2 - ((n +1) % 2), domid, handle);
> +   }
> +}
> +
> +/* Returns the array index of the tpmif domid/handle. Returns -1 if no
> such tpmif exists */
> +int get_tpmif_index(domid_t domid, unsigned int handle)
> +{
> +   int flags;
> +   int index;
> +   local_irq_save(flags);
> +   index = __get_tpmif_index(0, gtpmdev.num_tpms, domid, handle);
> +   local_irq_restore(flags);
> +   return index;
> +}
> +
> +/* Returns the tpmif domid/handle or NULL if none exists */
> +tpmif_t* get_tpmif(domid_t domid, unsigned int handle)
> +{
> +   int flags;
> +   int i;
> +   tpmif_t* ret;
> +   local_irq_save(flags);
> +   i = get_tpmif_index(domid, handle);
> +   if (i < 0) {
> +      ret = NULL;
> +   } else {
> +      ret = gtpmdev.tpmlist[i];
> +   }
> +   local_irq_restore(flags);
> +   return ret;
> +}
> +
> +/* Remove the given tpmif. Returns 0 if it was removed, -1 if it was
> not removed */
> +int remove_tpmif(tpmif_t* tpmif)
> +{
> +   int i, j;
> +   char* err;
> +   int flags;
> +   local_irq_save(flags);
> +
> +   /* Find the index in the array if it exists */
> +   i = get_tpmif_index(tpmif->domid, tpmif->handle);
> +   if (i < 0) {
> +      goto error;
> +   }
> +
> +   /* Remove the interface from the list */
> +   for(j = i; j < gtpmdev.num_tpms - 1; ++j) {
> +      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j+1];
> +   }
> +   gtpmdev.tpmlist[j] = NULL;
> +   --gtpmdev.num_tpms;
> +
> +   /* If removed tpm was the only ready tpm, then we need to check and
> turn off the ready flag */
> +   tpmdev_check_req();
> +
> +   local_irq_restore(flags);
> +
> +   /* Stop listening for events on this tpm interface */
> +   if((err = xenbus_unwatch_path_token(XBT_NIL, tpmif->fe_state_path,
> tpmif->fe_state_path))) {
> +      TPMBACK_ERR("Unable to unwatch path token `%s' Error was %s
> Ignoring..\n", tpmif->fe_state_path, err);
> +      free(err);
> +   }
> +
> +   return 0;
> +error:
> +   local_irq_restore(flags);
> +   return -1;
> +}
> +
> +/* Insert tpmif into dev->tpmlist. Returns 0 on success and non zero on
> error.
> + * It is an error to insert a tpmif with the same domid and handle
> + * number
> + * as something already in the list */
> +int insert_tpmif(tpmif_t* tpmif)
> +{
> +   int flags;
> +   unsigned int i, j;
> +   tpmif_t* tmp;
> +   char* err;
> +
> +   local_irq_save(flags);
> +
> +   /*Check if we need to allocate more space */
> +   if (gtpmdev.num_tpms == gtpmdev.num_alloc) {
> +      gtpmdev.num_alloc *= 2;
> +      gtpmdev.tpmlist = realloc(gtpmdev.tpmlist, gtpmdev.num_alloc);
> +   }
> +
> +   /*Find where to put the new interface */
> +   for(i = 0; i < gtpmdev.num_tpms; ++i)
> +   {
> +      tmp = gtpmdev.tpmlist[i];
> +      if(tpmif->domid == tmp->domid && tpmif->handle == tmp->handle) {
> +     TPMBACK_ERR("Tried to insert duplicate tpm interface %u/%u\n",
> (unsigned int) tpmif->domid, tpmif->handle);
> +     goto error;
> +      }
> +      if((tpmif->domid < tmp->domid) ||
> +        (tpmif->domid == tmp->domid && tpmif->handle < tmp->handle)) {
> +     break;
> +      }
> +   }
> +
> +   /*Shift all the tpm pointers past i down one */
> +   for(j = gtpmdev.num_tpms; j > i; --j) {
> +      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j-1];
> +   }
> +
> +   /*Add the new interface */
> +   gtpmdev.tpmlist[i] = tpmif;
> +   ++gtpmdev.num_tpms;
> +
> +   /*Should not be needed, anything inserted with ready flag is
> probably an error */
> +   tpmdev_check_req();
> +
> +   local_irq_restore(flags);
> +
> +   /*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)))
> +   {
> +      /* if we got an error here we should carefully remove the
> interface and then return */
> +      TPMBACK_ERR("Unable to watch path token `%s' Error was %s\n",
> tpmif->fe_state_path, err);
> +      free(err);
> +      remove_tpmif(tpmif);
> +      goto error_post_irq;
> +   }
> +
> +   return 0;
> +error:
> +   local_irq_restore(flags);
> +error_post_irq:
> +   return -1;
> +}
> +
> +
> +/*****************
> + * CHANGE BACKEND STATE
> + * *****************/
> +/*Attempts to change the backend state in xenstore
> + * returns 0 on success and non-zero on error */
> +int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state)
> +{
> +   char path[512];
> +   char *value;
> +   char *err;
> +   enum xenbus_state readst;
> +   TPMBACK_DEBUG("Backend state change %u/%u from=%d to=%d\n",
> (unsigned int) tpmif->domid, tpmif->handle, tpmif->state, state);
> +   if (tpmif->state == state)
> +      return 0;
> +
> +   snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int)
> tpmif->domid, tpmif->handle);
> +
> +   if((err = xenbus_read(XBT_NIL, path, &value))) {
> +      TPMBACK_ERR("Unable to read backend state %s, error was %s\n",
> path, err);
> +      free(err);
> +      return -1;
> +   }
> +   if(sscanf(value, "%d", &readst) != 1) {
> +      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
> +      free(value);
> +      return -1;
> +   }
> +   free(value);
> +
> +   /* It's possible that the backend state got updated by hotplug or
> something else behind our back */
> +   if(readst != tpmif->state) {
> +      TPMBACK_DEBUG("tpm interface state was %d but xenstore state was
> %d!\n", tpmif->state, readst);
> +      tpmif->state = readst;
> +   }
> +
> +   /*If if the state isnt changing, then we dont update xenstore b/c we
> dont want to fire extraneous events */
> +   if(tpmif->state == state) {
> +      return 0;
> +   }
> +
> +   /*update xenstore*/
> +   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
> tpmif->domid, tpmif->handle);
> +   if((err = xenbus_printf(XBT_NIL, path, "state", "%u", state))) {
> +      TPMBACK_ERR("Error writing to xenstore %s, error was %s new
> state=%d\n", path, err, state);
> +      free(err);
> +      return -1;
> +   }
> +
> +   tpmif->state = state;
> +
> +   return 0;
> +}
> +/**********************************
> + * TPMIF CREATION AND DELETION
> + * *******************************/
> +inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle)
> +{
> +   tpmif_t* tpmif;
> +   tpmif = malloc(sizeof(*tpmif));
> +   tpmif->domid = domid;
> +   tpmif->handle = handle;
> +   tpmif->fe_path = NULL;
> +   tpmif->fe_state_path = NULL;
> +   tpmif->state = XenbusStateInitialising;
> +   tpmif->status = DISCONNECTED;
> +   tpmif->tx = NULL;
> +   tpmif->pages = NULL;
> +   tpmif->flags = 0;
> +   tpmif->uuid = NULL;
> +   return tpmif;
> +}
> +
> +void __free_tpmif(tpmif_t* tpmif)
> +{
> +   if(tpmif->pages) {
> +      free(tpmif->pages);
> +   }
> +   if(tpmif->fe_path) {
> +      free(tpmif->fe_path);
> +   }
> +   if(tpmif->fe_state_path) {
> +      free(tpmif->fe_state_path);
> +   }
> +   if(tpmif->uuid) {
> +      free(tpmif->uuid);
> +   }
> +   free(tpmif);
> +}
> +/* Creates a new tpm interface, adds it to the sorted array and returns it.
> + * returns NULL on error
> + * If the tpm interface already exists, it is returned*/
> +tpmif_t* new_tpmif(domid_t domid, unsigned int handle)
> +{
> +   tpmif_t* tpmif;
> +   char* err;
> +   char path[512];
> +
> +   /* Make sure we haven't already created this tpm
> +    * Double events can occur */
> +   if((tpmif = get_tpmif(domid, handle)) != NULL) {
> +      return tpmif;
> +   }
> +
> +   tpmif = __init_tpmif(domid, handle);
> +
> +   /* Get the uuid from xenstore */
> +   snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domid,
> handle);
> +   if((err = xenbus_read(XBT_NIL, path, &tpmif->uuid))) {
> +      TPMBACK_ERR("Error reading %s, Error = %s\n", path, err);
> +      free(err);
> +      goto error;
> +   }
> +
> +   /* Do the exclusive uuid check now */
> +   if(gtpmdev.exclusive_uuids != NULL) {
> +      char** ptr;
> +
> +      /* Check that its in the whitelist */
> +      for(ptr = gtpmdev.exclusive_uuids; *ptr != NULL; ++ptr) {
> +     if(!strcmp(tpmif->uuid, *ptr)) {
> +        break;
> +     }
> +      }
> +      /* If *ptr == NULL then we went through the whole list without a
> match, so close the connection */
> +      if(*ptr == NULL) {
> +     tpmif_change_state(tpmif, XenbusStateClosed);
> +     TPMBACK_ERR("Frontend %u/%u tried to connect with invalid
> uuid=%s\n", (unsigned int) domid, handle, tpmif->uuid);
> +     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;
> +   }
> +
> +   snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int)
> domid, handle);
> +   if((err = xenbus_read(XBT_NIL, path, &tpmif->fe_path))) {
> +      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s),
> Error = %s", path, err);
> +      free(err);
> +      goto error;
> +   }
> +
> +   /*Set the state path */
> +   tpmif->fe_state_path = malloc(strlen(tpmif->fe_path) + 7);
> +   strcpy(tpmif->fe_state_path, tpmif->fe_path);
> +   strcat(tpmif->fe_state_path, "/state");
> +
> +   if(insert_tpmif(tpmif)) {
> +      goto error;
> +   }
> +   TPMBACK_DEBUG("New tpmif %u/%u\n", (unsigned int) tpmif->domid,
> tpmif->handle);
> +   /* Do the callback now */
> +   if(gtpmdev.open_callback) {
> +      gtpmdev.open_callback(tpmif->domid, tpmif->handle);
> +   }
> +   return tpmif;
> +error:
> +   __free_tpmif(tpmif);
> +   return NULL;
> +
> +}
> +
> +/* Removes tpmif from dev->tpmlist and frees it's memory usage */
> +void free_tpmif(tpmif_t* tpmif)
> +{
> +   char* err;
> +   char path[512];
> +   TPMBACK_DEBUG("Free tpmif %u/%u\n", (unsigned int) tpmif->domid,
> tpmif->handle);
> +   if(tpmif->flags & TPMIF_CLOSED) {
> +      TPMBACK_ERR("Tried to free an instance twice! Theres a bug
> somewhere!\n");
> +      BUG();
> +   }
> +   tpmif->flags = TPMIF_CLOSED;
> +
> +   tpmif_change_state(tpmif, XenbusStateClosing);
> +
> +   /* Unmap share page and unbind event channel */
> +   if(tpmif->status == CONNECTED) {
> +      tpmif->status = DISCONNECTING;
> +      mask_evtchn(tpmif->evtchn);
> +
> +      if(gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1)) {
> +     TPMBACK_ERR("%u/%u Error occured while trying to unmap shared
> page\n", (unsigned int) tpmif->domid, tpmif->handle);
> +      }
> +
> +      unbind_evtchn(tpmif->evtchn);
> +   }
> +   tpmif->status = DISCONNECTED;
> +   tpmif_change_state(tpmif, XenbusStateClosed);
> +
> +   /* Do the callback now */
> +   if(gtpmdev.close_callback) {
> +      gtpmdev.close_callback(tpmif->domid, tpmif->handle);
> +   }
> +
> +   /* remove from array */
> +   remove_tpmif(tpmif);
> +
> +   /* Wake up anyone possibly waiting on this interface and let them
> exit */
> +   wake_up(&waitq);
> +   schedule();
> +
> +   /* Remove the old xenbus entries */
> +   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
> tpmif->domid, tpmif->handle);
> +   if((err = xenbus_rm(XBT_NIL, path))) {
> +      TPMBACK_ERR("Error cleaning up xenbus entries path=%s
> error=%s\n", path, err);
> +      free(err);
> +   }
> +
> +   TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int)
> tpmif->domid, tpmif->handle);
> +
> +   /* free memory */
> +   __free_tpmif(tpmif);
> +
> +}
> +
> +/**********************
> + * REMAINING TPMBACK FUNCTIONS
> + * ********************/
> +
> +/*Event channel handler */
> +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);
> +
> +}
> +
> +/* Connect to frontend */
> +int connect_fe(tpmif_t* tpmif)
> +{
> +   char path[512];
> +   char* err, *value;
> +   uint32_t domid;
> +   grant_ref_t ringref;
> +   evtchn_port_t evtchn;
> +
> +   /* If already connected then quit */
> +   if (tpmif->status == CONNECTED) {
> +      TPMBACK_DEBUG("%u/%u tried to connect while it was already
> connected?\n", (unsigned int) tpmif->domid, tpmif->handle);
> +      return 0;
> +   }
> +
> +   /* Fetch the grant reference */
> +   snprintf(path, 512, "%s/ring-ref", tpmif->fe_path);
> +   if((err = xenbus_read(XBT_NIL, path, &value))) {
> +      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
> Error = %s", path, err);
> +      free(err);
> +      return -1;
> +   }
> +   if(sscanf(value, "%d", &ringref) != 1) {
> +      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
> +      free(value);
> +      return -1;
> +   }
> +   free(value);
> +
> +
> +   /* Fetch the event channel*/
> +   snprintf(path, 512, "%s/event-channel", tpmif->fe_path);
> +   if((err = xenbus_read(XBT_NIL, path, &value))) {
> +      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
> Error = %s", path, err);
> +      free(err);
> +      return -1;
> +   }
> +   if(sscanf(value, "%d", &evtchn) != 1) {
> +      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
> +      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) {
> +      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)))
> +   {
> +      TPMBACK_ERR("%u/%u Unable to bind to interdomain event
> channel!\n", (unsigned int) tpmif->domid, tpmif->handle);
> +      goto error_post_map;
> +   }
> +   unmask_evtchn(tpmif->evtchn);
> +
> +   /* Write the ready flag and change status to connected */
> +   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
> tpmif->domid, tpmif->handle);
> +   if((err = xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) {
> +      TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n",
> (unsigned int) tpmif->domid, tpmif->handle);
> +      free(err);
> +      goto error_post_evtchn;
> +   }
> +   tpmif->status = CONNECTED;
> +   if((tpmif_change_state(tpmif, XenbusStateConnected))){
> +      goto error_post_evtchn;
> +   }
> +
> +   TPMBACK_LOG("Frontend %u/%u connected\n", (unsigned int)
> tpmif->domid, tpmif->handle);
> +
> +   return 0;
> +error_post_evtchn:
> +   mask_evtchn(tpmif->evtchn);
> +   unbind_evtchn(tpmif->evtchn);
> +error_post_map:
> +   gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1);
> +   return -1;
> +}
> +
> +static int frontend_changed(tpmif_t* tpmif)
> +{
> +   int state = xenbus_read_integer(tpmif->fe_state_path);
> +   if(state < 0) {
> +      state = XenbusStateUnknown;
> +   }
> +
> +   TPMBACK_DEBUG("Frontend %u/%u state changed to %d\n", (unsigned int)
> tpmif->domid, tpmif->handle, state);
> +
> +   switch (state) {
> +      case XenbusStateInitialising:
> +      case XenbusStateInitialised:
> +     break;
> +
> +      case XenbusStateConnected:
> +     if(connect_fe(tpmif)) {
> +        TPMBACK_ERR("Failed to connect to front end %u/%u\n", (unsigned
> int) tpmif->domid, tpmif->handle);
> +        tpmif_change_state(tpmif, XenbusStateClosed);
> +        return -1;
> +     }
> +     break;
> +
> +      case XenbusStateClosing:
> +     tpmif_change_state(tpmif, XenbusStateClosing);
> +     break;
> +
> +      case XenbusStateUnknown: /* keep it here */
> +      case XenbusStateClosed:
> +     free_tpmif(tpmif);
> +     break;
> +
> +      default:
> +     TPMBACK_DEBUG("BAD STATE CHANGE %u/%u state = %d for tpmif\n",
> (unsigned int) tpmif->domid, tpmif->handle, state);
> +     return -1;
> +   }
> +   return 0;
> +}
> +
> +
> +/* parses the string that comes out of xenbus_watch_wait_return. */
> +static int parse_eventstr(const char* evstr, domid_t* domid, unsigned
> int* handle)
> +{
> +   int ret;
> +   char cmd[40];
> +   char* err;
> +   char* value;
> +   unsigned int udomid = 0;
> +   tpmif_t* tpmif;
> +   /* First check for new frontends, this occurs when
> /backend/vtpm/<domid>/<handle> gets created. Note we what the sscanf to
> fail on the last %s */
> +   if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd)
> == 2) {
> +      *domid = udomid;
> +      /* Make sure the entry exists, if this event triggers because the
> entry dissapeared then ignore it */
> +      if((err = xenbus_read(XBT_NIL, evstr, &value))) {
> +     free(err);
> +     return EV_NONE;
> +      }
> +      free(value);
> +      /* Make sure the tpmif entry does not already exist, this should
> not happen */
> +      if((tpmif = get_tpmif(*domid, *handle)) != NULL) {
> +     TPMBACK_DEBUG("Duplicate tpm entries! %u %u\n", tpmif->domid,
> tpmif->handle);
> +     return EV_NONE;
> +      }
> +      return EV_NEWFE;
> +   } else if((ret = sscanf(evstr,
> "/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) == 3) {
> +      *domid = udomid;
> +      if (!strcmp(cmd, "state"))
> +     return EV_STCHNG;
> +   }
> +   return EV_NONE;
> +}
> +
> +void handle_backend_event(char* evstr) {
> +   tpmif_t* tpmif;
> +   domid_t domid;
> +   unsigned int handle;
> +   int event;
> +
> +   TPMBACK_DEBUG("Xenbus Event: %s\n", evstr);
> +
> +   event = parse_eventstr(evstr, &domid, &handle);
> +
> +   switch(event) {
> +      case EV_NEWFE:
> +     if(new_tpmif(domid, handle) == NULL) {
> +        TPMBACK_ERR("Failed to create new tpm instance %u/%u\n",
> (unsigned int) domid, handle);
> +     }
> +     wake_up(&waitq);
> +     break;
> +      case EV_STCHNG:
> +     if((tpmif = get_tpmif(domid, handle))) {
> +        frontend_changed(tpmif);
> +     } else {
> +        TPMBACK_DEBUG("Event Received for non-existant tpm!
> instance=%u/%u xenbus_event=%s\n", (unsigned int) domid, handle, evstr);
> +     }
> +     break;
> +   }
> +}
> +
> +/* Runs through the given path and creates events recursively
> + * for all of its children.
> + * @path - xenstore path to scan */
> +static void generate_backend_events(const char* path)
> +{
> +   char* err;
> +   int i, len;
> +   char **dirs;
> +   char *entry;
> +
> +   if((err = xenbus_ls(XBT_NIL, path, &dirs)) != NULL) {
> +      free(err);
> +      return;
> +   }
> +
> +   for(i = 0; dirs[i] != NULL; ++i) {
> +      len = strlen(path) + strlen(dirs[i]) + 2;
> +      entry = malloc(len);
> +      snprintf(entry, len, "%s/%s", path, dirs[i]);
> +
> +      /* Generate and handle event for the entry itself */
> +      handle_backend_event(entry);
> +
> +      /* Do children */
> +      generate_backend_events(entry);
> +
> +      /* Cleanup */
> +      free(entry);
> +      free(dirs[i]);
> +   }
> +   free(dirs);
> +   return;
> +}
> +
> +char* tpmback_get_uuid(domid_t domid, unsigned int handle)
> +{
> +   tpmif_t* tpmif;
> +   if((tpmif = get_tpmif(domid, handle)) == NULL) {
> +      TPMBACK_DEBUG("get_uuid() failed, %u/%u is an invalid
> frontend\n", (unsigned int) domid, handle);
> +      return NULL;
> +   }
> +
> +   return tpmif->uuid;
> +}
> +
> +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int))
> +{
> +   gtpmdev.open_callback = cb;
> +}
> +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int))
> +{
> +   gtpmdev.close_callback = cb;
> +}
> +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int))
> +{
> +   gtpmdev.suspend_callback = cb;
> +}
> +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int))
> +{
> +   gtpmdev.resume_callback = cb;
> +}
> +
> +static void event_listener(void)
> +{
> +   const char* bepath = "backend/vtpm";
> +   char **path;
> +   char* err;
> +
> +   /* Setup the backend device watch */
> +   if((err = xenbus_watch_path_token(XBT_NIL, bepath, bepath,
> &gtpmdev.events)) != NULL) {
> +      TPMBACK_ERR("xenbus_watch_path_token(%s) failed with error
> %s!\n", bepath, err);
> +      free(err);
> +      goto egress;
> +   }
> +
> +   /* Check for any frontends that connected before we set the watch.
> +    * This is almost guaranteed to happen if both domains are started
> +    * immediatly one after the other.
> +    * We do this by manually generating events on everything in the backend
> +    * path */
> +   generate_backend_events(bepath);
> +
> +   /* Wait and listen for changes in frontend connections */
> +   while(1) {
> +      path = xenbus_wait_for_watch_return(&gtpmdev.events);
> +
> +      /*If quit flag was set then exit */
> +      if(gtpmdev.flags & TPMIF_CLOSED) {
> +     TPMBACK_DEBUG("listener thread got quit event. Exiting..\n");
> +     free(path);
> +     break;
> +      }
> +      handle_backend_event(*path);
> +      free(path);
> +
> +   }
> +
> +   if((err = xenbus_unwatch_path_token(XBT_NIL, bepath, bepath)) != NULL) {
> +      free(err);
> +   }
> +egress:
> +   return;
> +}
> +
> +void event_thread(void* p) {
> +   event_listener();
> +}
> +
> +void init_tpmback(char** exclusive_uuids)
> +{
> +   if(!globalinit) {
> +      init_waitqueue_head(&waitq);
> +      globalinit = 1;
> +   }
> +   printk("============= Init TPM BACK ================\n");
> +   gtpmdev.tpmlist = malloc(sizeof(tpmif_t*) * DEF_ARRAY_SIZE);
> +   gtpmdev.num_alloc = DEF_ARRAY_SIZE;
> +   gtpmdev.num_tpms = 0;
> +   gtpmdev.flags = 0;
> +   gtpmdev.exclusive_uuids = exclusive_uuids;
> +
> +   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
> +   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
> +
> +   eventthread = create_thread("tpmback-listener", event_thread, NULL);
> +
> +}
> +
> +void shutdown_tpmback(void)
> +{
> +   /* Disable callbacks */
> +   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
> +   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
> +
> +   TPMBACK_LOG("Shutting down tpm backend\n");
> +   /* Set the quit flag */
> +   gtpmdev.flags = TPMIF_CLOSED;
> +
> +   //printk("num tpms is %d\n", gtpmdev.num_tpms);
> +   /*Free all backend instances */
> +   while(gtpmdev.num_tpms) {
> +      free_tpmif(gtpmdev.tpmlist[0]);
> +   }
> +   free(gtpmdev.tpmlist);
> +   gtpmdev.tpmlist = NULL;
> +   gtpmdev.num_alloc = 0;
> +
> +   /* Wake up anyone possibly waiting on the device and let them exit */
> +   wake_up(&waitq);
> +   schedule();
> +}
> +
> +inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int
> handle, char* uuid)
> +{
> +   tpmcmd->domid = domid;
> +   tpmcmd->handle = handle;
> +   tpmcmd->uuid = uuid;
> +   tpmcmd->req = NULL;
> +   tpmcmd->req_len = 0;
> +   tpmcmd->resp = NULL;
> +   tpmcmd->resp_len = 0;
> +}
> +
> +tpmcmd_t* get_request(tpmif_t* tpmif) {
> +   tpmcmd_t* cmd;
> +   tpmif_tx_request_t* tx;
> +   int offset;
> +   int tocopy;
> +   int i;
> +   uint32_t domid;
> +   int flags;
> +
> +   local_irq_save(flags);
> +
> +   /* Allocate the cmd object to hold the data */
> +   if((cmd = malloc(sizeof(*cmd))) == NULL) {
> +      goto error;
> +   }
> +   init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid);
> +
> +   tx = &tpmif->tx->ring[0].req;
> +   cmd->req_len = tx->size;
> +   /* 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);
> +
> +   }
> +
> +#ifdef TPMBACK_PRINT_DEBUG
> +   TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u",
> (unsigned int) tpmif->domid, tpmif->handle, cmd->req_len);
> +   for(i = 0; i < cmd->req_len; ++i) {
> +      if (!(i % 30)) {
> +     TPMBACK_DEBUG_MORE("\n");
> +      }
> +      TPMBACK_DEBUG_MORE("%02hhX ", cmd->req[i]);
> +   }
> +   TPMBACK_DEBUG_MORE("\n\n");
> +#endif
> +
> +   local_irq_restore(flags);
> +   return cmd;
> +error:
> +   if(cmd != NULL) {
> +      if (cmd->req != NULL) {
> +     free(cmd->req);
> +     cmd->req = NULL;
> +      }
> +      free(cmd);
> +      cmd = NULL;
> +   }
> +   local_irq_restore(flags);
> +   return NULL;
> +
> +}
> +
> +void send_response(tpmcmd_t* cmd, tpmif_t* tpmif)
> +{
> +   tpmif_tx_request_t* tx;
> +   int offset;
> +   int i;
> +   uint32_t domid;
> +   int tocopy;
> +   int flags;
> +
> +   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);
> +
> +   }
> +
> +#ifdef TPMBACK_PRINT_DEBUG
> +   TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int)
> tpmif->domid, tpmif->handle, cmd->resp_len);
> +   for(i = 0; i < cmd->resp_len; ++i) {
> +      if (!(i % 30)) {
> +     TPMBACK_DEBUG_MORE("\n");
> +      }
> +      TPMBACK_DEBUG_MORE("%02hhX ", cmd->resp[i]);
> +   }
> +   TPMBACK_DEBUG_MORE("\n\n");
> +#endif
> +   /* clear the ready flag and send the event channel notice to the
> frontend */
> +   tpmif_req_finished(tpmif);
> +   notify_remote_via_evtchn(tpmif->evtchn);
> +error:
> +   local_irq_restore(flags);
> +   return;
> +}
> +
> +tpmcmd_t* tpmback_req_any(void)
> +{
> +   int i;
> +   /* Block until something has a request */
> +   wait_event(waitq, (gtpmdev.flags & (TPMIF_REQ_READY | TPMIF_CLOSED)));
> +
> +   /* Check if were shutting down */
> +   if(gtpmdev.flags & TPMIF_CLOSED) {
> +      /* if something was waiting for us to give up the queue so it can
> shutdown, let it finish */
> +      schedule();
> +      return NULL;
> +   }
> +
> +   for(i = 0; i < gtpmdev.num_tpms; ++i) {
> +      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
> +     return get_request(gtpmdev.tpmlist[i]);
> +      }
> +   }
> +
> +   TPMBACK_ERR("backend request ready flag was set but no interfaces
> were actually ready\n");
> +   return NULL;
> +}
> +
> +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle)
> +{
> +   tpmif_t* tpmif;
> +   tpmif = get_tpmif(domid, handle);
> +   if(tpmif == NULL) {
> +      return NULL;
> +   }
> +
> +   wait_event(waitq, (tpmif->flags & (TPMIF_REQ_READY | TPMIF_CLOSED)
> || gtpmdev.flags & TPMIF_CLOSED));
> +
> +   /* Check if were shutting down */
> +   if(tpmif->flags & TPMIF_CLOSED || gtpmdev.flags & TPMIF_CLOSED) {
> +      /* if something was waiting for us to give up the queue so it can
> free this instance, let it finish */
> +      schedule();
> +      return NULL;
> +   }
> +
> +   return get_request(tpmif);
> +}
> +
> +void tpmback_resp(tpmcmd_t* tpmcmd)
> +{
> +   tpmif_t* tpmif;
> +
> +   /* Get the associated interface, if it doesnt exist then just quit */
> +   tpmif = get_tpmif(tpmcmd->domid, tpmcmd->handle);
> +   if(tpmif == NULL) {
> +      TPMBACK_ERR("Tried to send a reponse to non existant frontend
> %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
> +      goto end;
> +   }
> +
> +   if(!(tpmif->flags & TPMIF_REQ_READY)) {
> +      TPMBACK_ERR("Tried to send response to a frontend that was not
> waiting for one %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
> +      goto end;
> +   }
> +
> +   /* Send response to frontend */
> +   send_response(tpmcmd, tpmif);
> +
> +end:
> +   if(tpmcmd->req != NULL) {
> +      free(tpmcmd->req);
> +   }
> +   free(tpmcmd);
> +   return;
> +}
> +
> +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int *handle)
> +{
> +   tpmif_t* tpmif;
> +   int flags;
> +   wait_event(waitq, ((gtpmdev.num_tpms > 0) || gtpmdev.flags &
> TPMIF_CLOSED));
> +   if(gtpmdev.flags & TPMIF_CLOSED) {
> +      return -1;
> +   }
> +   local_irq_save(flags);
> +   tpmif = gtpmdev.tpmlist[0];
> +   *domid = tpmif->domid;
> +   *handle = tpmif->handle;
> +   local_irq_restore(flags);
> +
> +   return 0;
> +}
> +
> +int tpmback_num_frontends(void)
> +{
> +   return gtpmdev.num_tpms;
> +}
> diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c
> --- /dev/null
> +++ b/extras/mini-os/tpmfront.c
> @@ -0,0 +1,606 @@
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * This driver 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, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This driver is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Based upon the files:
> + *  drivers/char/tpm/tpm_vtpm.c
> + *  drivers/char/tpm/tpm_xen.c
> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
> + */
> +#include <mini-os/os.h>
> +#include <mini-os/xenbus.h>
> +#include <mini-os/xmalloc.h>
> +#include <mini-os/events.h>
> +#include <mini-os/wait.h>
> +#include <mini-os/gnttab.h>
> +#include <xen/io/xenbus.h>
> +#include <xen/io/tpmif.h>
> +#include <mini-os/tpmfront.h>
> +#include <fcntl.h>
> +
> +//#define TPMFRONT_PRINT_DEBUG
> +#ifdef TPMFRONT_PRINT_DEBUG
> +#define TPMFRONT_DEBUG(fmt,...) printk("Tpmfront:Debug("__FILE__":%d) "
> fmt, __LINE__, ##__VA_ARGS__)
> +#define TPMFRONT_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
> +#else
> +#define TPMFRONT_DEBUG(fmt,...)
> +#endif
> +#define TPMFRONT_ERR(fmt,...) printk("Tpmfront:Error " fmt, ##__VA_ARGS__)
> +#define TPMFRONT_LOG(fmt,...) printk("Tpmfront:Info " fmt, ##__VA_ARGS__)
> +
> +#define min(a,b) (((a) < (b)) ? (a) : (b))
> +
> +void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void
> *data) {
> +   struct tpmfront_dev* dev = (struct tpmfront_dev*) data;
> +   /*If we get a response when we didnt make a request, just ignore it */
> +   if(!dev->waiting) {
> +      return;
> +   }
> +
> +   dev->waiting = 0;
> +#ifdef HAVE_LIBC
> +   if(dev->fd >= 0) {
> +      files[dev->fd].read = 1;
> +   }
> +#endif
> +   wake_up(&dev->waitq);
> +}
> +
> +static int publish_xenbus(struct tpmfront_dev* dev) {
> +   xenbus_transaction_t xbt;
> +   int retry;
> +   char* err;
> +   /* Write the grant reference and event channel to xenstore */
> +again:
> +   if((err = xenbus_transaction_start(&xbt))) {
> +      TPMFRONT_ERR("Unable to start xenbus transaction, error was
> %s\n", err);
> +      free(err);
> +      return -1;
> +   }
> +
> +   if((err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
> (unsigned int) dev->ring_ref))) {
> +      TPMFRONT_ERR("Unable to write %s/ring-ref, error was %s\n",
> dev->nodename, err);
> +      free(err);
> +      goto abort_transaction;
> +   }
> +
> +   if((err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
> (unsigned int) dev->evtchn))) {
> +      TPMFRONT_ERR("Unable to write %s/event-channel, error was %s\n",
> dev->nodename, err);
> +      free(err);
> +      goto abort_transaction;
> +   }
> +
> +   if((err = xenbus_transaction_end(xbt, 0, &retry))) {
> +      TPMFRONT_ERR("Unable to complete xenbus transaction, error was
> %s\n", err);
> +      free(err);
> +      return -1;
> +   }
> +   if(retry) {
> +      goto again;
> +   }
> +
> +   return 0;
> +abort_transaction:
> +   if((err = xenbus_transaction_end(xbt, 1, &retry))) {
> +      free(err);
> +   }
> +   return -1;
> +}
> +
> +static int wait_for_backend_connect(xenbus_event_queue* events, char* path)
> +{
> +   int state;
> +
> +   TPMFRONT_LOG("Waiting for backend connection..\n");
> +   /* Wait for the backend to connect */
> +   while(1) {
> +      state = xenbus_read_integer(path);
> +      if ( state < 0)
> +     state = XenbusStateUnknown;
> +      switch(state) {
> +     /* Bad states, we quit with error */
> +     case XenbusStateUnknown:
> +     case XenbusStateClosing:
> +     case XenbusStateClosed:
> +        TPMFRONT_ERR("Unable to connect to backend\n");
> +        return -1;
> +     /* If backend is connected then break out of loop */
> +     case XenbusStateConnected:
> +        TPMFRONT_LOG("Backend Connected\n");
> +        return 0;
> +     default:
> +        xenbus_wait_for_watch(events);
> +      }
> +   }
> +
> +}
> +
> +static int wait_for_backend_closed(xenbus_event_queue* events, char* path)
> +{
> +   int state;
> +
> +   TPMFRONT_LOG("Waiting for backend to close..\n");
> +   while(1) {
> +      state = xenbus_read_integer(path);
> +      if ( state < 0)
> +     state = XenbusStateUnknown;
> +      switch(state) {
> +     case XenbusStateUnknown:
> +        TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n");
> +        return -1;
> +     case XenbusStateClosed:
> +        TPMFRONT_LOG("Backend Closed\n");
> +        return 0;
> +     default:
> +        xenbus_wait_for_watch(events);
> +      }
> +   }
> +
> +}
> +
> +static int wait_for_backend_state_changed(struct tpmfront_dev* dev,
> XenbusState state) {
> +   char* err;
> +   int ret = 0;
> +   xenbus_event_queue events = NULL;
> +   char path[512];
> +
> +   snprintf(path, 512, "%s/state", dev->bepath);
> +   /*Setup the watch to wait for the backend */
> +   if((err = xenbus_watch_path_token(XBT_NIL, path, path, &events))) {
> +      TPMFRONT_ERR("Could not set a watch on %s, error was %s\n", path,
> err);
> +      free(err);
> +      return -1;
> +   }
> +
> +   /* Do the actual wait loop now */
> +   switch(state) {
> +      case XenbusStateConnected:
> +     ret = wait_for_backend_connect(&events, path);
> +     break;
> +      case XenbusStateClosed:
> +     ret = wait_for_backend_closed(&events, path);
> +     break;
> +      default:
> +     break;
> +   }
> +
> +   if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) {
> +      TPMFRONT_ERR("Unable to unwatch %s, error was %s, ignoring..\n",
> path, err);
> +      free(err);
> +   }
> +   return ret;
> +}
> +
> +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) {
> +      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);
> +   TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref);
> +
> +   /*Create event channel */
> +   if(evtchn_alloc_unbound(dev->bedomid, tpmfront_handler, dev,
> &dev->evtchn)) {
> +      TPMFRONT_ERR("Unable to allocate event channel\n");
> +      goto error_postmap;
> +   }
> +   unmask_evtchn(dev->evtchn);
> +   TPMFRONT_DEBUG("event channel is %lu\n", (unsigned long) dev->evtchn);
> +
> +   /* Write the entries to xenstore */
> +   if(publish_xenbus(dev)) {
> +      goto error_postevtchn;
> +   }
> +
> +   /* Change state to connected */
> +   dev->state = XenbusStateConnected;
> +
> +   /* Tell the backend that we are ready */
> +   if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
> dev->state))) {
> +      TPMFRONT_ERR("Unable to write to xenstore %s/state, value=%u",
> dev->nodename, XenbusStateConnected);
> +      free(err);
> +      goto error;
> +   }
> +
> +   return 0;
> +error_postevtchn:
> +      mask_evtchn(dev->evtchn);
> +      unbind_evtchn(dev->evtchn);
> +error_postmap:
> +      gnttab_end_access(dev->ring_ref);
> +      free_page(dev->tx);
> +error:
> +   return -1;
> +}
> +
> +struct tpmfront_dev* init_tpmfront(const char* _nodename)
> +{
> +   struct tpmfront_dev* dev;
> +   const char* nodename;
> +   char path[512];
> +   char* value, *err;
> +   unsigned long long ival;
> +   int i;
> +
> +   printk("============= Init TPM Front ================\n");
> +
> +   dev = malloc(sizeof(struct tpmfront_dev));
> +   memset(dev, 0, sizeof(struct tpmfront_dev));
> +
> +#ifdef HAVE_LIBC
> +   dev->fd = -1;
> +#endif
> +
> +   nodename = _nodename ? _nodename : "device/vtpm/0";
> +   dev->nodename = strdup(nodename);
> +
> +   init_waitqueue_head(&dev->waitq);
> +
> +   /* Get backend domid */
> +   snprintf(path, 512, "%s/backend-id", dev->nodename);
> +   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;
> +   }
> +   if(sscanf(value, "%llu", &ival) != 1) {
> +      TPMFRONT_ERR("%s has non-integer value (%s)\n", path, value);
> +      free(value);
> +      goto error;
> +   }
> +   free(value);
> +   dev->bedomid = ival;
> +
> +   /* Get backend xenstore path */
> +   snprintf(path, 512, "%s/backend", dev->nodename);
> +   if((err = xenbus_read(XBT_NIL, path, &dev->bepath))) {
> +      TPMFRONT_ERR("Unable to read %s during tpmfront initialization!
> error = %s\n", path, err);
> +      free(err);
> +      goto error;
> +   }
> +
> +   /* Create and publish grant reference and event channel */
> +   if (tpmfront_connect(dev)) {
> +      goto error;
> +   }
> +
> +   /* Wait for backend to connect */
> +   if( wait_for_backend_state_changed(dev, XenbusStateConnected)) {
> +      goto error;
> +   }
> +
> +   /* Allocate pages that will contain the messages */
> +   dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE);
> +   if(dev->pages == NULL) {
> +      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;
> +      }
> +   }
> +
> +   TPMFRONT_LOG("Initialization Completed successfully\n");
> +
> +   return dev;
> +
> +error:
> +   shutdown_tpmfront(dev);
> +   return NULL;
> +}
> +void shutdown_tpmfront(struct tpmfront_dev* dev)
> +{
> +   char* err;
> +   char path[512];
> +   int i;
> +   tpmif_tx_request_t* tx;
> +   if(dev == NULL) {
> +      return;
> +   }
> +   TPMFRONT_LOG("Shutting down tpmfront\n");
> +   /* disconnect */
> +   if(dev->state == XenbusStateConnected) {
> +      dev->state = XenbusStateClosing;
> +      //FIXME: Transaction for this?
> +      /* Tell backend we are closing */
> +      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
> (unsigned int) dev->state))) {
> +     free(err);
> +      }
> +
> +      /* Clean up xenstore entries */
> +      snprintf(path, 512, "%s/event-channel", dev->nodename);
> +      if((err = xenbus_rm(XBT_NIL, path))) {
> +     free(err);
> +      }
> +      snprintf(path, 512, "%s/ring-ref", dev->nodename);
> +      if((err = xenbus_rm(XBT_NIL, path))) {
> +     free(err);
> +      }
> +
> +      /* Tell backend we are closed */
> +      dev->state = XenbusStateClosed;
> +      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
> (unsigned int) dev->state))) {
> +     TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename,
> err);
> +     free(err);
> +      }
> +
> +      /* 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);
> +
> +   }
> +
> +   /* Cleanup memory usage */
> +   if(dev->respbuf) {
> +      free(dev->respbuf);
> +   }
> +   if(dev->bepath) {
> +      free(dev->bepath);
> +   }
> +   if(dev->nodename) {
> +      free(dev->nodename);
> +   }
> +   free(dev);
> +}
> +
> +int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t
> length)
> +{
> +   int i;
> +   tpmif_tx_request_t* tx = NULL;
> +   /* Error Checking */
> +   if(dev == NULL || dev->state != XenbusStateConnected) {
> +      TPMFRONT_ERR("Tried to send message through disconnected
> frontend\n");
> +      return -1;
> +   }
> +
> +#ifdef TPMFRONT_PRINT_DEBUG
> +   TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length);
> +   for(i = 0; i < length; ++i) {
> +      if(!(i % 30)) {
> +     TPMFRONT_DEBUG_MORE("\n");
> +      }
> +      TPMFRONT_DEBUG_MORE("%02X ", msg[i]);
> +   }
> +   TPMFRONT_DEBUG_MORE("\n");
> +#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;
> +   }
> +   dev->waiting = 1;
> +   dev->resplen = 0;
> +#ifdef HAVE_LIBC
> +   if(dev->fd >= 0) {
> +      files[dev->fd].read = 0;
> +      files[dev->fd].tpmfront.respgot = 0;
> +      files[dev->fd].tpmfront.offset = 0;
> +   }
> +#endif
> +   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;
> +   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));
> +
> +   /* Initialize */
> +   *msg = NULL;
> +   *length = 0;
> +
> +   /* 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;
> +   }
> +   /* 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;
> +   }
> +#ifdef TPMFRONT_PRINT_DEBUG
> +   TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned
> int) *length);
> +   for(i = 0; i < *length; ++i) {
> +      if(!(i % 30)) {
> +     TPMFRONT_DEBUG_MORE("\n");
> +      }
> +      TPMFRONT_DEBUG_MORE("%02X ", (*msg)[i]);
> +   }
> +   TPMFRONT_DEBUG_MORE("\n");
> +#endif
> +#ifdef HAVE_LIBC
> +   if(dev->fd >= 0) {
> +      files[dev->fd].tpmfront.respgot = 1;
> +   }
> +#endif
> +quit:
> +   return 0;
> +}
> +
> +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
> uint8_t** resp, size_t* resplen)
> +{
> +   int rc;
> +   if((rc = tpmfront_send(dev, req, reqlen))) {
> +      return rc;
> +   }
> +   if((rc = tpmfront_recv(dev, resp, resplen))) {
> +      return rc;
> +   }
> +
> +   return 0;
> +}
> +
> +#ifdef HAVE_LIBC
> +#include <errno.h>
> +int tpmfront_open(struct tpmfront_dev* dev)
> +{
> +   /* Silently prevent multiple opens */
> +   if(dev->fd != -1) {
> +      return dev->fd;
> +   }
> +
> +   dev->fd = alloc_fd(FTYPE_TPMFRONT);
> +   printk("tpmfront_open(%s) -> %d\n", dev->nodename, dev->fd);
> +   files[dev->fd].tpmfront.dev = dev;
> +   files[dev->fd].tpmfront.offset = 0;
> +   files[dev->fd].tpmfront.respgot = 0;
> +   return dev->fd;
> +}
> +
> +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count)
> +{
> +   int rc;
> +   struct tpmfront_dev* dev;
> +   dev = files[fd].tpmfront.dev;
> +
> +   if(count == 0) {
> +      return 0;
> +   }
> +
> +   /* Return an error if we are already processing a command */
> +   if(dev->waiting) {
> +      errno = EINPROGRESS;
> +      return -1;
> +   }
> +   /* Send the command now */
> +   if((rc = tpmfront_send(dev, buf, count)) != 0) {
> +      errno = EIO;
> +      return -1;
> +   }
> +   return count;
> +}
> +
> +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count)
> +{
> +   int rc;
> +   uint8_t* dummybuf;
> +   size_t dummysz;
> +   struct tpmfront_dev* dev;
> +
> +   dev = files[fd].tpmfront.dev;
> +
> +   if(count == 0) {
> +      return 0;
> +   }
> +
> +   /* get the response if we haven't already */
> +   if(files[dev->fd].tpmfront.respgot == 0) {
> +      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
> +     errno = EIO;
> +     return -1;
> +      }
> +   }
> +
> +   /* handle EOF case */
> +   if(files[dev->fd].tpmfront.offset >= dev->resplen) {
> +      return 0;
> +   }
> +
> +   /* Compute the number of bytes and do the copy operation */
> +   if((rc = min(count, dev->resplen - files[dev->fd].tpmfront.offset))
> != 0) {
> +      memcpy(buf, dev->respbuf + files[dev->fd].tpmfront.offset, rc);
> +      files[dev->fd].tpmfront.offset += rc;
> +   }
> +
> +   return rc;
> +}
> +
> +int tpmfront_posix_fstat(int fd, struct stat* buf)
> +{
> +   uint8_t* dummybuf;
> +   size_t dummysz;
> +   int rc;
> +   struct tpmfront_dev* dev = files[fd].tpmfront.dev;
> +
> +   /* If we have a response waiting, then read it now from the backend
> +    * so we can get its length*/
> +   if(dev->waiting || (files[dev->fd].read == 1 &&
> !files[dev->fd].tpmfront.respgot)) {
> +      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
> +     errno = EIO;
> +     return -1;
> +      }
> +   }
> +
> +   buf->st_mode = O_RDWR;
> +   buf->st_uid = 0;
> +   buf->st_gid = 0;
> +   buf->st_size = dev->resplen;
> +   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
> +
> +   return 0;
> +}
> +
> +
> +#endif
> --
> 1.7.4.4
>
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
>

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-18 18:24   ` Matthew Fioravante
@ 2012-09-26 13:30     ` George Dunlap
  2012-09-26 14:31       ` Matthew Fioravante
  2012-09-26 21:43       ` Samuel Thibault
  0 siblings, 2 replies; 10+ messages in thread
From: George Dunlap @ 2012-09-26 13:30 UTC (permalink / raw)
  To: Matthew Fioravante; +Cc: Samuel Thibault, xen-devel, Ian Campbell

On Tue, Sep 18, 2012 at 7:24 PM, Matthew Fioravante
<matthew.fioravante@jhuapl.edu> wrote:
> Is there anyone on the dev list that is familiar enough to review it?
>
> I can tell you we have been using all 3 of these drivers internally for
> about 2 years now without issue. All of them are basically ports of the
> linux drivers to mini-os.

If you're willing to be the TPM maintainer (which would involve adding
your name to the MAINTAINERS file), and if Samuel is OK with you
owning the tpm-related files in stubdom, I think it wouldn't
necessarily need a thorough review to get in, as long as people are
happy with how it integrates with the rest of the code.  What do
people think?

 -George

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-26 13:25 ` George Dunlap
@ 2012-09-26 14:29   ` Matthew Fioravante
  0 siblings, 0 replies; 10+ messages in thread
From: Matthew Fioravante @ 2012-09-26 14:29 UTC (permalink / raw)
  To: George Dunlap; +Cc: Samuel Thibault, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 117157 bytes --]

On 09/26/2012 09:25 AM, George Dunlap wrote:
> On Mon, Sep 17, 2012 at 11:08 PM, Matthew Fioravante
> <matthew.fioravante@jhuapl.edu> wrote:
>> This patch adds 3 new drivers to mini-os.
>>
>> tpmfront - paravirtualized tpm frontend driver
>> tpmback - paravirtualized tpm backend driver
>> tpm_tis - hardware tpm driver
> Just trying to understand this -- tpmback is so that you can run a
> vtpm instance in the stubdom.  But what is tmpfront for?  Is that for
> running qemu stub domains?
>
>  -George
tpmfront and tpmback are like traditional frontend/backend
paravirtualized xen drivers. vtpm-stubdom uses tpmback to talk to the
linux guest. tpmfront and tpmback are also used by vtpm-stubdom and
vtpmmgrdom to communicate with one another.

The driver chain looks like this.

linux guest [tpm_xenu] -> [tpmback] vtpm-stubdom
[tpmfront]->[tpmback]vtpmmgrdom[tpm_tis]->TPM


>
>> Unfortunately these drivers were derived from GPL licensed linux kernel
>> drivers so they must carry the GPL license. However, since mini-os now
>> supports conditional compilation, hopefully these drivers can be
>> included into the xen tree and conditionally removed from non-gpl
>> projects. By default they are disabled in the makefile.
>>
>> Signed off by: Matthew Fioravante matthew.fioravante@jhuapl.edu
>>
>> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
>> --- a/extras/mini-os/Makefile
>> +++ b/extras/mini-os/Makefile
>> @@ -22,6 +22,9 @@ CONFIG_QEMU_XS_ARGS ?= n
>>  CONFIG_TEST ?= n
>>  CONFIG_PCIFRONT ?= n
>>  CONFIG_BLKFRONT ?= y
>> +CONFIG_TPMFRONT ?= n
>> +CONFIG_TPM_TIS ?= n
>> +CONFIG_TPMBACK ?= n
>>  CONFIG_NETFRONT ?= y
>>  CONFIG_FBFRONT ?= y
>>  CONFIG_KBDFRONT ?= y
>> @@ -36,6 +39,9 @@ flags-$(CONFIG_SPARSE_BSS) += -DCONFIG_SPARSE_BSS
>>  flags-$(CONFIG_QEMU_XS_ARGS) += -DCONFIG_QEMU_XS_ARGS
>>  flags-$(CONFIG_PCIFRONT) += -DCONFIG_PCIFRONT
>>  flags-$(CONFIG_BLKFRONT) += -DCONFIG_BLKFRONT
>> +flags-$(CONFIG_TPMFRONT) += -DCONFIG_TPMFRONT
>> +flags-$(CONFIG_TPM_TIS) += -DCONFIG_TPM_TIS
>> +flags-$(CONFIG_TPMBACK) += -DCONFIG_TPMBACK
>>  flags-$(CONFIG_NETFRONT) += -DCONFIG_NETFRONT
>>  flags-$(CONFIG_KBDFRONT) += -DCONFIG_KBDFRONT
>>  flags-$(CONFIG_FBFRONT) += -DCONFIG_FBFRONT
>> @@ -67,6 +73,9 @@ TARGET := mini-os
>>  SUBDIRS := lib xenbus console
>>
>>  src-$(CONFIG_BLKFRONT) += blkfront.c
>> +src-$(CONFIG_TPMFRONT) += tpmfront.c
>> +src-$(CONFIG_TPM_TIS) += tpm_tis.c
>> +src-$(CONFIG_TPMBACK) += tpmback.c
>>  src-y += daytime.c
>>  src-y += events.c
>>  src-$(CONFIG_FBFRONT) += fbfront.c
>> diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h
>> --- a/extras/mini-os/include/lib.h
>> +++ b/extras/mini-os/include/lib.h
>> @@ -142,6 +142,8 @@ enum fd_type {
>>      FTYPE_FB,
>>      FTYPE_MEM,
>>      FTYPE_SAVEFILE,
>> +    FTYPE_TPMFRONT,
>> +    FTYPE_TPM_TIS,
>>  };
>>
>>  LIST_HEAD(evtchn_port_list, evtchn_port_info);
>> @@ -185,6 +187,20 @@ extern struct file {
>>      struct {
>>          struct consfront_dev *dev;
>>      } cons;
>> +#ifdef CONFIG_TPMFRONT
>> +    struct {
>> +       struct tpmfront_dev *dev;
>> +       int respgot;
>> +       off_t offset;
>> +    } tpmfront;
>> +#endif
>> +#ifdef CONFIG_TPM_TIS
>> +    struct {
>> +       struct tpm_chip *dev;
>> +       int respgot;
>> +       off_t offset;
>> +    } tpm_tis;
>> +#endif
>>  #ifdef CONFIG_XENBUS
>>          struct {
>>              /* To each xenbus FD is associated a queue of watch events
>> for this
>> diff --git a/extras/mini-os/include/tpm_tis.h
>> b/extras/mini-os/include/tpm_tis.h
>> --- /dev/null
>> +++ b/extras/mini-os/include/tpm_tis.h
>> @@ -0,0 +1,63 @@
>> +/*
>> + * Copyright (c) 2010-2012 United States Government, as represented by
>> + * the Secretary of Defense.  All rights reserved.
>> + *
>> + * This driver 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, either version 3 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This driver is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Based upon the files:
>> + *  drivers/char/tpm/tpm_tis.c
>> + *  drivers/char/tpm/tpm.c
>> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
>> + */
>> +#ifndef TPM_TIS_H
>> +#define TPM_TIS_H
>> +
>> +#include <mini-os/types.h>
>> +#include <mini-os/byteorder.h>
>> +
>> +#define TPM_TIS_EN_LOCL0 1
>> +#define TPM_TIS_EN_LOCL1 (1 << 1)
>> +#define TPM_TIS_EN_LOCL2 (1 << 2)
>> +#define TPM_TIS_EN_LOCL3 (1 << 3)
>> +#define TPM_TIS_EN_LOCL4 (1 << 4)
>> +#define TPM_TIS_EN_LOCLALL (TPM_TIS_EN_LOCL0 | TPM_TIS_EN_LOCL1  |
>> TPM_TIS_EN_LOCL2 | TPM_TIS_EN_LOCL3 | TPM_TIS_EN_LOCL4)
>> +#define TPM_TIS_LOCL_INT_TO_FLAG(x) (1 << x)
>> +#define TPM_BASEADDR 0xFED40000
>> +#define TPM_PROBE_IRQ 0xFFFF
>> +
>> +struct tpm_chip;
>> +
>> +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
>> unsigned int irq);
>> +void shutdown_tpm_tis(struct tpm_chip* tpm);
>> +
>> +int tpm_tis_request_locality(struct tpm_chip* tpm, int locality);
>> +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
>> uint8_t** resp, size_t* resplen);
>> +
>> +#ifdef HAVE_LIBC
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +/* POSIX IO functions:
>> + * use tpm_tis_open() to get a file descriptor to the tpm device
>> + * use write() on the fd to send a command to the backend. You must
>> + * include the entire command in a single call to write().
>> + * use read() on the fd to read the response. You can use
>> + * fstat() to get the size of the response and lseek() to seek on it.
>> + */
>> +int tpm_tis_open(struct tpm_chip* tpm);
>> +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count);
>> +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count);
>> +int tpm_tis_posix_fstat(int fd, struct stat* buf);
>> +#endif
>> +
>> +#endif
>> diff --git a/extras/mini-os/include/tpmback.h
>> b/extras/mini-os/include/tpmback.h
>> --- /dev/null
>> +++ b/extras/mini-os/include/tpmback.h
>> @@ -0,0 +1,95 @@
>> +/*
>> + * Copyright (c) 2010-2012 United States Government, as represented by
>> + * the Secretary of Defense.  All rights reserved.
>> + *
>> + * This driver 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, either version 3 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This driver is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Based upon the files:
>> + *  drivers/xen/tpmbk.c
>> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
>> + */
>> +#include <xen/io/tpmif.h>
>> +#include <xen/io/xenbus.h>
>> +#include <mini-os/types.h>
>> +#include <xen/xen.h>
>> +#ifndef TPMBACK_H
>> +#define TPMBACK_H
>> +
>> +struct tpmcmd {
>> +   domid_t domid;        /* Domid of the frontend */
>> +   unsigned int handle;    /* Handle of the frontend */
>> +   char* uuid;            /* uuid of the tpm interface - allocated
>> internally, dont free it */
>> +
>> +   unsigned int req_len;        /* Size of the command in buf - set by
>> tpmback driver */
>> +   uint8_t* req;            /* tpm command bits, allocated by driver,
>> DON'T FREE IT */
>> +   unsigned int resp_len;    /* Size of the outgoing command,
>> +                   you set this before passing the cmd object to
>> tpmback_resp */
>> +   uint8_t* resp;        /* Buffer for response - YOU MUST ALLOCATE IT,
>> YOU MUST ALSO FREE IT */
>> +};
>> +typedef struct tpmcmd tpmcmd_t;
>> +
>> +/* Initialize the tpm backend driver
>> + * @exclusive_domname - This is NULL terminated list of vtpm uuid
>> strings. If this list
>> + *             is non-empty, then only frontend domains with vtpm
>> uuid's matching
>> + *             entries in this list will be allowed to connect.
>> + *             Other connections will be immediatly closed.
>> + *             Set this argument to NULL to allow any vtpm to connect.
>> + */
>> +void init_tpmback(char** exclusive_uuids);
>> +/* Shutdown tpm backend driver */
>> +void shutdown_tpmback(void);
>> +
>> +/* Blocks until a tpm command is sent from any front end.
>> + * Returns a pointer to the tpm command to handle.
>> + * Do not try to free this pointer or the req buffer
>> + * This function will return NULL if the tpm backend driver
>> + * is shutdown or any other error occurs */
>> +tpmcmd_t* tpmback_req_any(void);
>> +
>> +/* Blocks until a tpm command from the frontend at domid/handle
>> + * is sent.
>> + * Returns NULL if domid/handle is not connected, tpmback is
>> + * shutdown or shutting down, or if there is an error
>> + */
>> +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle);
>> +
>> +/* Send the response to the tpm command back to the frontend
>> + * This function will free the tpmcmd object, but you must free the resp
>> + * buffer yourself */
>> +void tpmback_resp(tpmcmd_t* tpmcmd);
>> +
>> +/* Waits for the first frontend to connect and then sets domid and
>> handle appropriately.
>> + * If one or more frontends are already connected, this will set domid
>> and handle to one
>> + * of them arbitrarily. The main use for this function is to wait until
>> a single
>> + * frontend connection has occured.
>> + * returns 0 on success, non-zero on failure */
>> +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int
>> *handle);
>> +
>> +/* returns the number of frontends connected */
>> +int tpmback_num_frontends(void);
>> +
>> +/* Returns the uuid of the specified frontend, NULL on error */
>> +char* tpmback_get_uuid(domid_t domid, unsigned int handle);
>> +
>> +/* Specify a function to call when a new tpm device connects */
>> +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int));
>> +
>> +/* Specify a function to call when a tpm device disconnects */
>> +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int));
>> +
>> +//Not Implemented
>> +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int));
>> +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int));
>> +
>> +#endif
>> diff --git a/extras/mini-os/include/tpmfront.h
>> b/extras/mini-os/include/tpmfront.h
>> --- /dev/null
>> +++ b/extras/mini-os/include/tpmfront.h
>> @@ -0,0 +1,94 @@
>> +/*
>> + * Copyright (c) 2010-2012 United States Government, as represented by
>> + * the Secretary of Defense.  All rights reserved.
>> + *
>> + * This driver 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, either version 3 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This driver is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Based upon the files:
>> + *  drivers/char/tpm/tpm_vtpm.c
>> + *  drivers/char/tpm/tpm_xen.c
>> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
>> + */
>> +#ifndef TPMFRONT_H
>> +#define TPMFRONT_H
>> +
>> +#include <mini-os/types.h>
>> +#include <mini-os/os.h>
>> +#include <mini-os/events.h>
>> +#include <mini-os/wait.h>
>> +#include <xen/xen.h>
>> +#include <xen/io/xenbus.h>
>> +#include <xen/io/tpmif.h>
>> +
>> +struct tpmfront_dev {
>> +   grant_ref_t ring_ref;
>> +   evtchn_port_t evtchn;
>> +
>> +   tpmif_tx_interface_t* tx;
>> +
>> +   void** pages;
>> +
>> +   domid_t bedomid;
>> +   char* nodename;
>> +   char* bepath;
>> +
>> +   XenbusState state;
>> +
>> +   uint8_t waiting;
>> +   struct wait_queue_head waitq;
>> +
>> +   uint8_t* respbuf;
>> +   size_t resplen;
>> +
>> +#ifdef HAVE_LIBC
>> +   int fd;
>> +#endif
>> +
>> +};
>> +
>> +
>> +/*Initialize frontend */
>> +struct tpmfront_dev* init_tpmfront(const char* nodename);
>> +/*Shutdown frontend */
>> +void shutdown_tpmfront(struct tpmfront_dev* dev);
>> +
>> +/* Send a tpm command to the backend and wait for the response
>> + *
>> + * @dev - frontend device
>> + * @req - request buffer
>> + * @reqlen - length of request buffer
>> + * @resp - *resp will be set to internal response buffer, don't free
>> it! Value is undefined on error
>> + * @resplen - *resplen will be set to the length of the response. Value
>> is undefined on error
>> + *
>> + * returns 0 on success, non zero on failure.
>> + * */
>> +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
>> uint8_t** resp, size_t* resplen);
>> +
>> +#ifdef HAVE_LIBC
>> +#include <sys/stat.h>
>> +/* POSIX IO functions:
>> + * use tpmfront_open() to get a file descriptor to the tpm device
>> + * use write() on the fd to send a command to the backend. You must
>> + * include the entire command in a single call to write().
>> + * use read() on the fd to read the response. You can use
>> + * fstat() to get the size of the response and lseek() to seek on it.
>> + */
>> +int tpmfront_open(struct tpmfront_dev* dev);
>> +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count);
>> +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count);
>> +int tpmfront_posix_fstat(int fd, struct stat* buf);
>> +#endif
>> +
>> +
>> +#endif
>> diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
>> --- a/extras/mini-os/lib/sys.c
>> +++ b/extras/mini-os/lib/sys.c
>> @@ -27,6 +27,8 @@
>>  #include <netfront.h>
>>  #include <blkfront.h>
>>  #include <fbfront.h>
>> +#include <tpmfront.h>
>> +#include <tpm_tis.h>
>>  #include <xenbus.h>
>>  #include <xenstore.h>
>>
>> @@ -294,6 +296,16 @@ int read(int fd, void *buf, size_t nbytes)
>>          return blkfront_posix_read(fd, buf, nbytes);
>>          }
>>  #endif
>> +#ifdef CONFIG_TPMFRONT
>> +        case FTYPE_TPMFRONT: {
>> +        return tpmfront_posix_read(fd, buf, nbytes);
>> +        }
>> +#endif
>> +#ifdef CONFIG_TPM_TIS
>> +        case FTYPE_TPM_TIS: {
>> +        return tpm_tis_posix_read(fd, buf, nbytes);
>> +        }
>> +#endif
>>      default:
>>          break;
>>      }
>> @@ -330,6 +342,14 @@ int write(int fd, const void *buf, size_t nbytes)
>>      case FTYPE_BLK:
>>          return blkfront_posix_write(fd, buf, nbytes);
>>  #endif
>> +#ifdef CONFIG_TPMFRONT
>> +    case FTYPE_TPMFRONT:
>> +        return tpmfront_posix_write(fd, buf, nbytes);
>> +#endif
>> +#ifdef CONFIG_TPM_TIS
>> +    case FTYPE_TPM_TIS:
>> +        return tpm_tis_posix_write(fd, buf, nbytes);
>> +#endif
>>      default:
>>          break;
>>      }
>> @@ -341,8 +361,16 @@ int write(int fd, const void *buf, size_t nbytes)
>>  off_t lseek(int fd, off_t offset, int whence)
>>  {
>>      switch(files[fd].type) {
>> +#if defined(CONFIG_BLKFRONT) || defined(CONFIG_TPMFRONT) ||
>> defined(CONFIG_TPM_TIS)
>>  #ifdef CONFIG_BLKFRONT
>>         case FTYPE_BLK:
>> +#endif
>> +#ifdef CONFIG_TPMFRNT
>> +       case FTYPE_TPMFRONT:
>> +#endif
>> +#ifdef CONFIG_TPM_TIS
>> +       case FTYPE_TPM_TIS:
>> +#endif
>>        switch (whence) {
>>           case SEEK_SET:
>>          files[fd].file.offset = offset;
>> @@ -420,6 +448,18 @@ int close(int fd)
>>          files[fd].type = FTYPE_NONE;
>>          return 0;
>>  #endif
>> +#ifdef CONFIG_TPMFRONT
>> +    case FTYPE_TPMFRONT:
>> +            shutdown_tpmfront(files[fd].tpmfront.dev);
>> +        files[fd].type = FTYPE_NONE;
>> +        return 0;
>> +#endif
>> +#ifdef CONFIG_TPM_TIS
>> +    case FTYPE_TPM_TIS:
>> +            shutdown_tpm_tis(files[fd].tpm_tis.dev);
>> +        files[fd].type = FTYPE_NONE;
>> +        return 0;
>> +#endif
>>  #ifdef CONFIG_KBDFRONT
>>      case FTYPE_KBD:
>>              shutdown_kbdfront(files[fd].kbd.dev);
>> @@ -489,6 +529,14 @@ int fstat(int fd, struct stat *buf)
>>      case FTYPE_BLK:
>>         return blkfront_posix_fstat(fd, buf);
>>  #endif
>> +#ifdef CONFIG_TPMFRONT
>> +    case FTYPE_TPMFRONT:
>> +       return tpmfront_posix_fstat(fd, buf);
>> +#endif
>> +#ifdef CONFIG_TPM_TIS
>> +    case FTYPE_TPM_TIS:
>> +       return tpm_tis_posix_fstat(fd, buf);
>> +#endif
>>      default:
>>          break;
>>      }
>> diff --git a/extras/mini-os/tpm_tis.c b/extras/mini-os/tpm_tis.c
>> --- /dev/null
>> +++ b/extras/mini-os/tpm_tis.c
>> @@ -0,0 +1,1344 @@
>> +/*
>> + * Copyright (c) 2010-2012 United States Government, as represented by
>> + * the Secretary of Defense.  All rights reserved.
>> + *
>> + * This driver 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, either version 3 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This driver is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Based upon the files:
>> + *  drivers/char/tpm/tpm_tis.c
>> + *  drivers/char/tpm/tpm.c
>> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
>> + */
>> +#include <mini-os/ioremap.h>
>> +#include <mini-os/iorw.h>
>> +#include <mini-os/tpm_tis.h>
>> +#include <mini-os/os.h>
>> +#include <mini-os/sched.h>
>> +#include <mini-os/byteorder.h>
>> +#include <mini-os/events.h>
>> +#include <mini-os/wait.h>
>> +#include <mini-os/xmalloc.h>
>> +#include <errno.h>
>> +#include <stdbool.h>
>> +
>> +#ifndef min
>> +    #define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
>> +#endif
>> +
>> +#define TPM_HEADER_SIZE 10
>> +
>> +#define TPM_BUFSIZE 2048
>> +
>> +struct tpm_input_header {
>> +        uint16_t  tag;
>> +        uint32_t  length;
>> +        uint32_t  ordinal;
>> +}__attribute__((packed));
>> +
>> +struct tpm_output_header {
>> +        uint16_t  tag;
>> +        uint32_t  length;
>> +        uint32_t  return_code;
>> +}__attribute__((packed));
>> +
>> +struct  stclear_flags_t {
>> +        uint16_t  tag;
>> +        uint8_t      deactivated;
>> +        uint8_t      disableForceClear;
>> +        uint8_t      physicalPresence;
>> +        uint8_t      physicalPresenceLock;
>> +        uint8_t      bGlobalLock;
>> +}__attribute__((packed));
>> +
>> +struct  tpm_version_t {
>> +        uint8_t      Major;
>> +        uint8_t      Minor;
>> +        uint8_t      revMajor;
>> +        uint8_t      revMinor;
>> +}__attribute__((packed));
>> +
>> +struct  tpm_version_1_2_t {
>> +        uint16_t  tag;
>> +        uint8_t      Major;
>> +        uint8_t      Minor;
>> +        uint8_t      revMajor;
>> +        uint8_t      revMinor;
>> +}__attribute__((packed));
>> +
>> +struct  timeout_t {
>> +        uint32_t  a;
>> +        uint32_t  b;
>> +        uint32_t  c;
>> +        uint32_t  d;
>> +}__attribute__((packed));
>> +
>> +struct duration_t {
>> +        uint32_t  tpm_short;
>> +        uint32_t  tpm_medium;
>> +        uint32_t  tpm_long;
>> +}__attribute__((packed));
>> +
>> +struct permanent_flags_t {
>> +        uint16_t  tag;
>> +        uint8_t      disable;
>> +        uint8_t      ownership;
>> +        uint8_t      deactivated;
>> +        uint8_t      readPubek;
>> +        uint8_t      disableOwnerClear;
>> +        uint8_t      allowMaintenance;
>> +        uint8_t      physicalPresenceLifetimeLock;
>> +        uint8_t      physicalPresenceHWEnable;
>> +        uint8_t      physicalPresenceCMDEnable;
>> +        uint8_t      CEKPUsed;
>> +        uint8_t      TPMpost;
>> +        uint8_t      TPMpostLock;
>> +        uint8_t      FIPS;
>> +        uint8_t      operator;
>> +        uint8_t      enableRevokeEK;
>> +        uint8_t      nvLocked;
>> +        uint8_t      readSRKPub;
>> +        uint8_t      tpmEstablished;
>> +        uint8_t      maintenanceDone;
>> +        uint8_t      disableFullDALogicInfo;
>> +}__attribute__((packed));
>> +
>> +typedef union {
>> +        struct  permanent_flags_t perm_flags;
>> +        struct  stclear_flags_t stclear_flags;
>> +        bool    owned;
>> +        uint32_t  num_pcrs;
>> +        struct  tpm_version_t   tpm_version;
>> +        struct  tpm_version_1_2_t tpm_version_1_2;
>> +        uint32_t  manufacturer_id;
>> +        struct timeout_t  timeout;
>> +        struct duration_t duration;
>> +} cap_t;
>> +
>> +struct  tpm_getcap_params_in {
>> +        uint32_t  cap;
>> +        uint32_t  subcap_size;
>> +        uint32_t  subcap;
>> +}__attribute__((packed));
>> +
>> +struct  tpm_getcap_params_out {
>> +        uint32_t  cap_size;
>> +        cap_t   cap;
>> +}__attribute__((packed));
>> +
>> +struct  tpm_readpubek_params_out {
>> +        uint8_t      algorithm[4];
>> +        uint8_t      encscheme[2];
>> +        uint8_t      sigscheme[2];
>> +        uint32_t  paramsize;
>> +        uint8_t      parameters[12]; /*assuming RSA*/
>> +        uint32_t  keysize;
>> +        uint8_t      modulus[256];
>> +        uint8_t      checksum[20];
>> +}__attribute__((packed));
>> +
>> +typedef union {
>> +        struct  tpm_input_header in;
>> +        struct  tpm_output_header out;
>> +} tpm_cmd_header;
>> +
>> +#define TPM_DIGEST_SIZE 20
>> +struct tpm_pcrread_out {
>> +        uint8_t      pcr_result[TPM_DIGEST_SIZE];
>> +}__attribute__((packed));
>> +
>> +struct tpm_pcrread_in {
>> +        uint32_t  pcr_idx;
>> +}__attribute__((packed));
>> +
>> +struct tpm_pcrextend_in {
>> +        uint32_t  pcr_idx;
>> +        uint8_t      hash[TPM_DIGEST_SIZE];
>> +}__attribute__((packed));
>> +
>> +typedef union {
>> +        struct  tpm_getcap_params_out getcap_out;
>> +        struct  tpm_readpubek_params_out readpubek_out;
>> +        uint8_t      readpubek_out_buffer[sizeof(struct
>> tpm_readpubek_params_out)];
>> +        struct  tpm_getcap_params_in getcap_in;
>> +        struct  tpm_pcrread_in  pcrread_in;
>> +        struct  tpm_pcrread_out pcrread_out;
>> +        struct  tpm_pcrextend_in pcrextend_in;
>> +} tpm_cmd_params;
>> +
>> +struct tpm_cmd_t {
>> +        tpm_cmd_header  header;
>> +        tpm_cmd_params  params;
>> +}__attribute__((packed));
>> +
>> +
>> +enum tpm_duration {
>> +   TPM_SHORT = 0,
>> +   TPM_MEDIUM = 1,
>> +   TPM_LONG = 2,
>> +   TPM_UNDEFINED,
>> +};
>> +
>> +#define TPM_MAX_ORDINAL 243
>> +#define TPM_MAX_PROTECTED_ORDINAL 12
>> +#define TPM_PROTECTED_ORDINAL_MASK 0xFF
>> +
>> +extern const uint8_t
>> tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL];
>> +extern const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL];
>> +
>> +#define TPM_DIGEST_SIZE 20
>> +#define TPM_ERROR_SIZE 10
>> +#define TPM_RET_CODE_IDX 6
>> +
>> +/* tpm_capabilities */
>> +#define TPM_CAP_FLAG cpu_to_be32(4)
>> +#define TPM_CAP_PROP cpu_to_be32(5)
>> +#define CAP_VERSION_1_1 cpu_to_be32(0x06)
>> +#define CAP_VERSION_1_2 cpu_to_be32(0x1A)
>> +
>> +/* tpm_sub_capabilities */
>> +#define TPM_CAP_PROP_PCR cpu_to_be32(0x101)
>> +#define TPM_CAP_PROP_MANUFACTURER cpu_to_be32(0x103)
>> +#define TPM_CAP_FLAG_PERM cpu_to_be32(0x108)
>> +#define TPM_CAP_FLAG_VOL cpu_to_be32(0x109)
>> +#define TPM_CAP_PROP_OWNER cpu_to_be32(0x111)
>> +#define TPM_CAP_PROP_TIS_TIMEOUT cpu_to_be32(0x115)
>> +#define TPM_CAP_PROP_TIS_DURATION cpu_to_be32(0x120)
>> +
>> +
>> +#define TPM_INTERNAL_RESULT_SIZE 200
>> +#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
>> +#define TPM_ORD_GET_CAP cpu_to_be32(101)
>> +
>> +extern const struct tpm_input_header tpm_getcap_header;
>> +
>> +
>> +
>> +const uint8_t tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
>> +   TPM_UNDEFINED,          /* 0 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 5 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 10 */
>> +   TPM_SHORT,
>> +};
>> +
>> +const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
>> +   TPM_UNDEFINED,          /* 0 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 5 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 10 */
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,
>> +   TPM_LONG,
>> +   TPM_LONG,
>> +   TPM_MEDIUM,             /* 15 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,
>> +   TPM_LONG,
>> +   TPM_SHORT,              /* 20 */
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_SHORT,              /* 25 */
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,             /* 30 */
>> +   TPM_LONG,
>> +   TPM_MEDIUM,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,              /* 35 */
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_MEDIUM,             /* 40 */
>> +   TPM_LONG,
>> +   TPM_MEDIUM,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,              /* 45 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_LONG,
>> +   TPM_MEDIUM,             /* 50 */
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 55 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_MEDIUM,             /* 60 */
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,             /* 65 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 70 */
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 75 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_LONG,               /* 80 */
>> +   TPM_UNDEFINED,
>> +   TPM_MEDIUM,
>> +   TPM_LONG,
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,          /* 85 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 90 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,          /* 95 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_MEDIUM,             /* 100 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 105 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 110 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,              /* 115 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_LONG,               /* 120 */
>> +   TPM_LONG,
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,
>> +   TPM_SHORT,              /* 125 */
>> +   TPM_SHORT,
>> +   TPM_LONG,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,              /* 130 */
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,          /* 135 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 140 */
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 145 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 150 */
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,          /* 155 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 160 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 165 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_LONG,               /* 170 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 175 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_MEDIUM,             /* 180 */
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,             /* 185 */
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 190 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 195 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 200 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,
>> +   TPM_SHORT,              /* 205 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_MEDIUM,             /* 210 */
>> +   TPM_UNDEFINED,
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,          /* 215 */
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,
>> +   TPM_SHORT,              /* 220 */
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_SHORT,
>> +   TPM_UNDEFINED,          /* 225 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 230 */
>> +   TPM_LONG,
>> +   TPM_MEDIUM,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,          /* 235 */
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_UNDEFINED,
>> +   TPM_SHORT,              /* 240 */
>> +   TPM_UNDEFINED,
>> +   TPM_MEDIUM,
>> +};
>> +
>> +const struct tpm_input_header tpm_getcap_header = {
>> +        .tag = TPM_TAG_RQU_COMMAND,
>> +        .length = cpu_to_be32(22),
>> +        .ordinal = TPM_ORD_GET_CAP
>> +};
>> +
>> +
>> +enum tis_access {
>> +   TPM_ACCESS_VALID = 0x80,
>> +   TPM_ACCESS_ACTIVE_LOCALITY = 0x20,    /* (R) */
>> +   TPM_ACCESS_RELINQUISH_LOCALITY = 0x20,/* (W) */
>> +   TPM_ACCESS_REQUEST_PENDING = 0x04,    /* (W) */
>> +   TPM_ACCESS_REQUEST_USE = 0x02,    /* (W) */
>> +};
>> +
>> +enum tis_status {
>> +   TPM_STS_VALID = 0x80,        /* (R) */
>> +   TPM_STS_COMMAND_READY = 0x40,    /* (R) */
>> +   TPM_STS_DATA_AVAIL = 0x10,        /* (R) */
>> +   TPM_STS_DATA_EXPECT = 0x08,        /* (R) */
>> +   TPM_STS_GO = 0x20,            /* (W) */
>> +};
>> +
>> +enum tis_int_flags {
>> +   TPM_GLOBAL_INT_ENABLE = 0x80000000,
>> +   TPM_INTF_BURST_COUNT_STATIC = 0x100,
>> +   TPM_INTF_CMD_READY_INT = 0x080,
>> +   TPM_INTF_INT_EDGE_FALLING = 0x040,
>> +   TPM_INTF_INT_EDGE_RISING = 0x020,
>> +   TPM_INTF_INT_LEVEL_LOW = 0x010,
>> +   TPM_INTF_INT_LEVEL_HIGH = 0x008,
>> +   TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
>> +   TPM_INTF_STS_VALID_INT = 0x002,
>> +   TPM_INTF_DATA_AVAIL_INT = 0x001,
>> +};
>> +
>> +enum tis_defaults {
>> +   TIS_MEM_BASE = 0xFED40000,
>> +   TIS_MEM_LEN  = 0x5000,
>> +   TIS_SHORT_TIMEOUT = 750, /*ms*/
>> +   TIS_LONG_TIMEOUT = 2000, /*2 sec */
>> +};
>> +
>> +#define TPM_TIMEOUT 5
>> +
>> +#define TPM_ACCESS(t, l)                   (((uint8_t*)t->pages[l]) +
>> 0x0000)
>> +#define TPM_INT_ENABLE(t, l)
>> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0008))
>> +#define TPM_INT_VECTOR(t, l)               (((uint8_t*)t->pages[l]) +
>> 0x000C)
>> +#define TPM_INT_STATUS(t, l)               (((uint8_t*)t->pages[l]) +
>> 0x0010)
>> +#define TPM_INTF_CAPS(t, l)
>> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0014))
>> +#define TPM_STS(t, l)
>> ((uint8_t*)(((uint8_t*)t->pages[l]) + 0x0018))
>> +#define TPM_DATA_FIFO(t, l)                (((uint8_t*)t->pages[l]) +
>> 0x0024)
>> +
>> +#define TPM_DID_VID(t, l)
>> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0F00))
>> +#define TPM_RID(t, l)                      (((uint8_t*)t->pages[l]) +
>> 0x0F04)
>> +
>> +struct tpm_chip {
>> +   int enabled_localities;
>> +   int locality;
>> +   unsigned long baseaddr;
>> +   uint8_t* pages[5];
>> +   int did, vid, rid;
>> +
>> +   uint8_t data_buffer[TPM_BUFSIZE];
>> +   int data_len;
>> +
>> +   s_time_t timeout_a, timeout_b, timeout_c, timeout_d;
>> +   s_time_t duration[3];
>> +
>> +#ifdef HAVE_LIBC
>> +   int fd;
>> +#endif
>> +
>> +   unsigned int irq;
>> +   struct wait_queue_head read_queue;
>> +   struct wait_queue_head int_queue;
>> +};
>> +
>> +
>> +static void __init_tpm_chip(struct tpm_chip* tpm) {
>> +   tpm->enabled_localities = TPM_TIS_EN_LOCLALL;
>> +   tpm->locality = -1;
>> +   tpm->baseaddr = 0;
>> +   tpm->pages[0] = tpm->pages[1] = tpm->pages[2] = tpm->pages[3] =
>> tpm->pages[4] = NULL;
>> +   tpm->vid = 0;
>> +   tpm->did = 0;
>> +   tpm->irq = 0;
>> +   init_waitqueue_head(&tpm->read_queue);
>> +   init_waitqueue_head(&tpm->int_queue);
>> +
>> +   tpm->data_len = -1;
>> +
>> +#ifdef HAVE_LIBC
>> +   tpm->fd = -1;
>> +#endif
>> +}
>> +
>> +/*
>> + * Returns max number of nsecs to wait
>> + */
>> +s_time_t tpm_calc_ordinal_duration(struct tpm_chip *chip,
>> +      uint32_t ordinal)
>> +{
>> +   int duration_idx = TPM_UNDEFINED;
>> +   s_time_t duration = 0;
>> +
>> +   if (ordinal < TPM_MAX_ORDINAL)
>> +      duration_idx = tpm_ordinal_duration[ordinal];
>> +   else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
>> +     TPM_MAX_PROTECTED_ORDINAL)
>> +      duration_idx =
>> +     tpm_protected_ordinal_duration[ordinal &
>> +     TPM_PROTECTED_ORDINAL_MASK];
>> +
>> +   if (duration_idx != TPM_UNDEFINED) {
>> +      duration = chip->duration[duration_idx];
>> +   }
>> +
>> +   if (duration <= 0) {
>> +      return SECONDS(120);
>> +   }
>> +   else
>> +   {
>> +      return duration;
>> +   }
>> +}
>> +
>> +
>> +static int locality_enabled(struct tpm_chip* tpm, int l) {
>> +   return tpm->enabled_localities & (1 << l);
>> +}
>> +
>> +static int check_locality(struct tpm_chip* tpm, int l) {
>> +   if(locality_enabled(tpm, l) && (ioread8(TPM_ACCESS(tpm, l)) &
>> +        (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
>> +     (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
>> +      return l;
>> +   }
>> +   return -1;
>> +}
>> +
>> +void release_locality(struct tpm_chip* tpm, int l, int force)
>> +{
>> +   if (locality_enabled(tpm, l) && (force || (ioread8(TPM_ACCESS(tpm, l)) &
>> +           (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
>> +        (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))) {
>> +      iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_RELINQUISH_LOCALITY);
>> +   }
>> +}
>> +
>> +int tpm_tis_request_locality(struct tpm_chip* tpm, int l) {
>> +
>> +   s_time_t stop;
>> +   /*Make sure locality is valid */
>> +   if(!locality_enabled(tpm, l)) {
>> +      printk("tpm_tis_change_locality() Tried to change to locality %d,
>> but it is disabled or invalid!\n", l);
>> +      return -1;
>> +   }
>> +   /* Check if we already have the current locality */
>> +   if(check_locality(tpm, l) >= 0) {
>> +      return tpm->locality = l;
>> +   }
>> +   /* Set the new locality*/
>> +   iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_REQUEST_USE);
>> +
>> +   if(tpm->irq) {
>> +      /* Wait for interrupt */
>> +      wait_event_deadline(tpm->int_queue, (check_locality(tpm, l) >=
>> 0), NOW() + tpm->timeout_a);
>> +
>> +      /* FIXME: Handle timeout event, should return error in that case */
>> +      return l;
>> +   } else {
>> +      /* Wait for burstcount */
>> +      stop = NOW() + tpm->timeout_a;
>> +      do {
>> +     if(check_locality(tpm, l) >= 0) {
>> +        return tpm->locality = l;
>> +     }
>> +     msleep(TPM_TIMEOUT);
>> +      } while(NOW() < stop);
>> +   }
>> +
>> +   printk("REQ LOCALITY FAILURE\n");
>> +   return -1;
>> +}
>> +
>> +static uint8_t tpm_tis_status(struct tpm_chip* tpm) {
>> +   return ioread8(TPM_STS(tpm, tpm->locality));
>> +}
>> +
>> +/* This causes the current command to be aborted */
>> +static void tpm_tis_ready(struct tpm_chip* tpm) {
>> +   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_COMMAND_READY);
>> +}
>> +#define tpm_tis_cancel_cmd(v) tpm_tis_ready(v)
>> +
>> +static int get_burstcount(struct tpm_chip* tpm) {
>> +   s_time_t stop;
>> +   int burstcnt;
>> +
>> +   stop = NOW() + tpm->timeout_d;
>> +   do {
>> +      burstcnt = ioread8((TPM_STS(tpm, tpm->locality) + 1));
>> +      burstcnt += ioread8(TPM_STS(tpm, tpm->locality) + 2) << 8;
>> +
>> +      if (burstcnt) {
>> +     return burstcnt;
>> +      }
>> +      msleep(TPM_TIMEOUT);
>> +   } while(NOW() < stop);
>> +   return -EBUSY;
>> +}
>> +
>> +static int wait_for_stat(struct tpm_chip* tpm, uint8_t mask,
>> +      unsigned long timeout, struct wait_queue_head* queue) {
>> +   s_time_t stop;
>> +   uint8_t status;
>> +
>> +   status = tpm_tis_status(tpm);
>> +   if((status & mask) == mask) {
>> +      return 0;
>> +   }
>> +
>> +   if(tpm->irq) {
>> +      wait_event_deadline(*queue, ((tpm_tis_status(tpm) & mask) ==
>> mask), timeout);
>> +      /* FIXME: Check for timeout and return -ETIME */
>> +      return 0;
>> +   } else {
>> +      stop = NOW() + timeout;
>> +      do {
>> +     msleep(TPM_TIMEOUT);
>> +     status = tpm_tis_status(tpm);
>> +     if((status & mask) == mask)
>> +        return 0;
>> +      } while( NOW() < stop);
>> +   }
>> +   return -ETIME;
>> +}
>> +
>> +static int recv_data(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
>> +   int size = 0;
>> +   int burstcnt;
>> +   while( size < count &&
>> +     wait_for_stat(tpm,
>> +        TPM_STS_DATA_AVAIL | TPM_STS_VALID,
>> +        tpm->timeout_c,
>> +        &tpm->read_queue)
>> +     == 0) {
>> +      burstcnt = get_burstcount(tpm);
>> +      for(; burstcnt > 0 && size < count; --burstcnt)
>> +      {
>> +     buf[size++] = ioread8(TPM_DATA_FIFO(tpm, tpm->locality));
>> +      }
>> +   }
>> +   return size;
>> +}
>> +
>> +int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
>> +   int size = 0;
>> +   int expected, status;
>> +
>> +   if (count < TPM_HEADER_SIZE) {
>> +      size = -EIO;
>> +      goto out;
>> +   }
>> +
>> +   /* read first 10 bytes, including tag, paramsize, and result */
>> +   if((size =
>> +        recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
>> +      printk("Error reading tpm cmd header\n");
>> +      goto out;
>> +   }
>> +
>> +   expected = be32_to_cpu(*((uint32_t*)(buf + 2)));
>> +   if(expected > count) {
>> +      size = -EIO;
>> +      goto out;
>> +   }
>> +
>> +   if((size += recv_data(tpm, & buf[TPM_HEADER_SIZE],
>> +           expected - TPM_HEADER_SIZE)) < expected) {
>> +      printk("Unable to read rest of tpm command size=%d
>> expected=%d\n", size, expected);
>> +      size = -ETIME;
>> +      goto out;
>> +   }
>> +
>> +   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
>> +   status = tpm_tis_status(tpm);
>> +   if(status & TPM_STS_DATA_AVAIL) {
>> +      printk("Error: left over data\n");
>> +      size = -EIO;
>> +      goto out;
>> +   }
>> +
>> +out:
>> +   tpm_tis_ready(tpm);
>> +   release_locality(tpm, tpm->locality, 0);
>> +   return size;
>> +}
>> +int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) {
>> +   int rc;
>> +   int status, burstcnt = 0;
>> +   int count = 0;
>> +   uint32_t ordinal;
>> +
>> +   if(tpm_tis_request_locality(tpm, tpm->locality) < 0) {
>> +      return -EBUSY;
>> +   }
>> +
>> +   status = tpm_tis_status(tpm);
>> +   if((status & TPM_STS_COMMAND_READY) == 0) {
>> +      tpm_tis_ready(tpm);
>> +      if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b,
>> &tpm->int_queue) < 0) {
>> +     rc = -ETIME;
>> +     goto out_err;
>> +      }
>> +   }
>> +
>> +   while(count < len - 1) {
>> +      burstcnt = get_burstcount(tpm);
>> +      for(;burstcnt > 0 && count < len -1; --burstcnt) {
>> +     iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]);
>> +      }
>> +
>> +      wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
>> +      status = tpm_tis_status(tpm);
>> +      if((status & TPM_STS_DATA_EXPECT) == 0) {
>> +     rc = -EIO;
>> +     goto out_err;
>> +      }
>> +   }
>> +
>> +   /*Write last byte*/
>> +   iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]);
>> +   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue);
>> +   status = tpm_tis_status(tpm);
>> +   if((status & TPM_STS_DATA_EXPECT) != 0) {
>> +      rc = -EIO;
>> +      goto out_err;
>> +   }
>> +
>> +   /*go and do it*/
>> +   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO);
>> +
>> +   if(tpm->irq) {
>> +      /*Wait for interrupt */
>> +      ordinal = be32_to_cpu(*(buf + 6));
>> +      if(wait_for_stat(tpm,
>> +           TPM_STS_DATA_AVAIL | TPM_STS_VALID,
>> +           tpm_calc_ordinal_duration(tpm, ordinal),
>> +           &tpm->read_queue) < 0) {
>> +     rc = -ETIME;
>> +     goto out_err;
>> +      }
>> +   }
>> +#ifdef HAVE_LIBC
>> +   if(tpm->fd >= 0) {
>> +      files[tpm->fd].read = 0;
>> +      files[tpm->fd].tpm_tis.respgot = 0;
>> +      files[tpm->fd].tpm_tis.offset = 0;
>> +   }
>> +#endif
>> +   return len;
>> +
>> +out_err:
>> +   tpm_tis_ready(tpm);
>> +   release_locality(tpm, tpm->locality, 0);
>> +   return rc;
>> +}
>> +
>> +static void tpm_tis_irq_handler(evtchn_port_t port, struct pt_regs
>> *regs, void* data)
>> +{
>> +   struct tpm_chip* tpm = data;
>> +   uint32_t interrupt;
>> +   int i;
>> +
>> +   interrupt = ioread32(TPM_INT_STATUS(tpm, tpm->locality));
>> +   if(interrupt == 0) {
>> +      return;
>> +   }
>> +
>> +   if(interrupt & TPM_INTF_DATA_AVAIL_INT) {
>> +      wake_up(&tpm->read_queue);
>> +   }
>> +   if(interrupt & TPM_INTF_LOCALITY_CHANGE_INT) {
>> +      for(i = 0; i < 5; ++i) {
>> +     if(check_locality(tpm, i) >= 0) {
>> +        break;
>> +     }
>> +      }
>> +   }
>> +   if(interrupt & (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
>> +        TPM_INTF_CMD_READY_INT)) {
>> +      wake_up(&tpm->int_queue);
>> +   }
>> +
>> +   /* Clear interrupts handled with TPM_EOI */
>> +   iowrite32(TPM_INT_STATUS(tpm, tpm->locality), interrupt);
>> +   ioread32(TPM_INT_STATUS(tpm, tpm->locality));
>> +   return;
>> +}
>> +
>> +/*
>> + * Internal kernel interface to transmit TPM commands
>> + */
>> +static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf,
>> +      size_t bufsiz)
>> +{
>> +   ssize_t rc;
>> +   uint32_t count, ordinal;
>> +   s_time_t stop;
>> +
>> +   count = be32_to_cpu(*((uint32_t *) (buf + 2)));
>> +   ordinal = be32_to_cpu(*((uint32_t *) (buf + 6)));
>> +   if (count == 0)
>> +      return -ENODATA;
>> +   if (count > bufsiz) {
>> +      printk("Error: invalid count value %x %zx \n", count, bufsiz);
>> +      return -E2BIG;
>> +   }
>> +
>> +   //down(&chip->tpm_mutex);
>> +
>> +   if ((rc = tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) {
>> +      printk("tpm_transmit: tpm_send: error %zd\n", rc);
>> +      goto out;
>> +   }
>> +
>> +   if (chip->irq)
>> +      goto out_recv;
>> +
>> +   stop = NOW() + tpm_calc_ordinal_duration(chip, ordinal);
>> +   do {
>> +      uint8_t status = tpm_tis_status(chip);
>> +      if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) ==
>> +        (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
>> +     goto out_recv;
>> +
>> +      if ((status == TPM_STS_COMMAND_READY)) {
>> +     printk("TPM Error: Operation Canceled\n");
>> +     rc = -ECANCELED;
>> +     goto out;
>> +      }
>> +
>> +      msleep(TPM_TIMEOUT);    /* CHECK */
>> +      rmb();
>> +   } while (NOW() < stop);
>> +
>> +   /* Cancel the command */
>> +   tpm_tis_cancel_cmd(chip);
>> +   printk("TPM Operation Timed out\n");
>> +   rc = -ETIME;
>> +   goto out;
>> +
>> +out_recv:
>> +   if((rc = tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) {
>> +      printk("tpm_transmit: tpm_recv: error %d\n", rc);
>> +   }
>> +out:
>> +   //up(&chip->tpm_mutex);
>> +   return rc;
>> +}
>> +
>> +static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
>> +                            int len, const char *desc)
>> +{
>> +        int err;
>> +
>> +        len = tpm_transmit(chip,(uint8_t *) cmd, len);
>> +        if (len <  0)
>> +                return len;
>> +        if (len == TPM_ERROR_SIZE) {
>> +                err = be32_to_cpu(cmd->header.out.return_code);
>> +                printk("A TPM error (%d) occurred %s\n", err, desc);
>> +                return err;
>> +        }
>> +        return 0;
>> +}
>> +
>> +void tpm_get_timeouts(struct tpm_chip *chip)
>> +{
>> +   struct tpm_cmd_t tpm_cmd;
>> +   struct timeout_t *timeout_cap;
>> +   struct duration_t *duration_cap;
>> +   ssize_t rc;
>> +   uint32_t timeout;
>> +
>> +   tpm_cmd.header.in = tpm_getcap_header;
>> +   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
>> +   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>> +   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
>> +
>> +   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
>> +     "attempting to determine the timeouts")) != 0) {
>> +      printk("transmit failed %d\n", rc);
>> +      goto duration;
>> +   }
>> +
>> +   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
>> +     != 4 * sizeof(uint32_t)) {
>> +      printk("Out len check failure %lu \n",
>> be32_to_cpu(tpm_cmd.header.out.length));
>> +      goto duration;
>> +   }
>> +
>> +   timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
>> +   /* Don't overwrite default if value is 0 */
>> +   timeout = be32_to_cpu(timeout_cap->a);
>> +   if (timeout)
>> +      chip->timeout_a = MICROSECS(timeout); /*Convert to msec */
>> +   timeout = be32_to_cpu(timeout_cap->b);
>> +   if (timeout)
>> +      chip->timeout_b = MICROSECS(timeout); /*Convert to msec */
>> +   timeout = be32_to_cpu(timeout_cap->c);
>> +   if (timeout)
>> +      chip->timeout_c = MICROSECS(timeout); /*Convert to msec */
>> +   timeout = be32_to_cpu(timeout_cap->d);
>> +   if (timeout)
>> +      chip->timeout_d = MICROSECS(timeout); /*Convert to msec */
>> +
>> +duration:
>> +   tpm_cmd.header.in = tpm_getcap_header;
>> +   tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
>> +   tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>> +   tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
>> +
>> +   if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
>> +     "attempting to determine the durations")) < 0) {
>> +      return;
>> +   }
>> +
>> +   if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size)
>> +     != 3 * sizeof(uint32_t)) {
>> +      return;
>> +   }
>> +        duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
>> +        chip->duration[TPM_SHORT] = be32_to_cpu(duration_cap->tpm_short);
>> +        /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets
>> the above
>> +         * value wrong and apparently reports msecs rather than usecs.
>> So we
>> +         * fix up the resulting too-small TPM_SHORT value to make
>> things work.
>> +         */
>> +        if (chip->duration[TPM_SHORT] < 10) {
>> +       chip->duration[TPM_SHORT] = MILLISECS(chip->duration[TPM_SHORT]);
>> +    } else {
>> +       chip->duration[TPM_SHORT] = MICROSECS(chip->duration[TPM_SHORT]);
>> +    }
>> +
>> +        chip->duration[TPM_MEDIUM] =
>> MICROSECS(be32_to_cpu(duration_cap->tpm_medium));
>> +        chip->duration[TPM_LONG] =
>> MICROSECS(be32_to_cpu(duration_cap->tpm_long));
>> +}
>> +
>> +
>> +
>> +void tpm_continue_selftest(struct tpm_chip* chip) {
>> +   uint8_t data[] = {
>> +      0, 193,                 /* TPM_TAG_RQU_COMMAND */
>> +      0, 0, 0, 10,            /* length */
>> +      0, 0, 0, 83,            /* TPM_ORD_GetCapability */
>> +   };
>> +
>> +   tpm_transmit(chip, data, sizeof(data));
>> +}
>> +
>> +ssize_t tpm_getcap(struct tpm_chip *chip, uint32_t subcap_id, cap_t *cap,
>> +                   const char *desc)
>> +{
>> +        struct tpm_cmd_t tpm_cmd;
>> +        int rc;
>> +
>> +        tpm_cmd.header.in = tpm_getcap_header;
>> +        if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
>> +                tpm_cmd.params.getcap_in.cap = subcap_id;
>> +                /*subcap field not necessary */
>> +                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
>> +                tpm_cmd.header.in.length -= cpu_to_be32(sizeof(uint32_t));
>> +        } else {
>> +                if (subcap_id == TPM_CAP_FLAG_PERM ||
>> +                    subcap_id == TPM_CAP_FLAG_VOL)
>> +                        tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
>> +                else
>> +                        tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
>> +                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>> +                tpm_cmd.params.getcap_in.subcap = subcap_id;
>> +        }
>> +        rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
>> +        if (!rc)
>> +                *cap = tpm_cmd.params.getcap_out.cap;
>> +        return rc;
>> +}
>> +
>> +
>> +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,
>> unsigned int irq)
>> +{
>> +   int i;
>> +   unsigned long addr;
>> +   struct tpm_chip* tpm = NULL;
>> +   uint32_t didvid;
>> +   uint32_t intfcaps;
>> +   uint32_t intmask;
>> +
>> +   printk("============= Init TPM TIS Driver ==============\n");
>> +
>> +   /*Sanity check the localities input */
>> +   if(localities & ~TPM_TIS_EN_LOCLALL) {
>> +      printk("init_tpm_tis() Invalid locality specification! %X\n",
>> localities);
>> +      goto abort_egress;
>> +   }
>> +
>> +   printk("IOMEM Machine Base Address: %lX\n", baseaddr);
>> +
>> +   /* Create the tpm data structure */
>> +   tpm = malloc(sizeof(struct tpm_chip));
>> +   __init_tpm_chip(tpm);
>> +
>> +   /* Set the enabled localities - if 0 we leave default as all enabled */
>> +   if(localities != 0) {
>> +      tpm->enabled_localities = localities;
>> +   }
>> +   printk("Enabled Localities: ");
>> +   for(i = 0; i < 5; ++i) {
>> +      if(locality_enabled(tpm, i)) {
>> +     printk("%d ", i);
>> +      }
>> +   }
>> +   printk("\n");
>> +
>> +   /* Set the base machine address */
>> +   tpm->baseaddr = baseaddr;
>> +
>> +   /* Set default timeouts */
>> +   tpm->timeout_a = MILLISECS(TIS_SHORT_TIMEOUT);
>> +   tpm->timeout_b = MILLISECS(TIS_LONG_TIMEOUT);
>> +   tpm->timeout_c = MILLISECS(TIS_SHORT_TIMEOUT);
>> +   tpm->timeout_d = MILLISECS(TIS_SHORT_TIMEOUT);
>> +
>> +   /*Map the mmio pages */
>> +   addr = tpm->baseaddr;
>> +   for(i = 0; i < 5; ++i) {
>> +      if(locality_enabled(tpm, i)) {
>> +     /* Map the page in now */
>> +     if((tpm->pages[i] = ioremap_nocache(addr, PAGE_SIZE)) == NULL) {
>> +        printk("Unable to map iomem page a address %p\n", addr);
>> +        goto abort_egress;
>> +     }
>> +
>> +     /* Set default locality to the first enabled one */
>> +     if (tpm->locality < 0) {
>> +        if(tpm_tis_request_locality(tpm, i) < 0) {
>> +           printk("Unable to request locality %d??\n", i);
>> +           goto abort_egress;
>> +        }
>> +     }
>> +      }
>> +      addr += PAGE_SIZE;
>> +   }
>> +
>> +
>> +   /* Get the vendor and device ids */
>> +   didvid = ioread32(TPM_DID_VID(tpm, tpm->locality));
>> +   tpm->did = didvid >> 16;
>> +   tpm->vid = didvid & 0xFFFF;
>> +
>> +
>> +   /* Get the revision id */
>> +   tpm->rid = ioread8(TPM_RID(tpm, tpm->locality));
>> +
>> +   printk("1.2 TPM (device-id=0x%X vendor-id = %X rev-id = %X)\n",
>> tpm->did, tpm->vid, tpm->rid);
>> +
>> +   intfcaps = ioread32(TPM_INTF_CAPS(tpm, tpm->locality));
>> +   printk("TPM interface capabilities (0x%x):\n", intfcaps);
>> +   if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
>> +      printk("\tBurst Count Static\n");
>> +   if (intfcaps & TPM_INTF_CMD_READY_INT)
>> +      printk("\tCommand Ready Int Support\n");
>> +   if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
>> +      printk("\tInterrupt Edge Falling\n");
>> +   if (intfcaps & TPM_INTF_INT_EDGE_RISING)
>> +      printk("\tInterrupt Edge Rising\n");
>> +   if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
>> +      printk("\tInterrupt Level Low\n");
>> +   if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
>> +      printk("\tInterrupt Level High\n");
>> +   if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
>> +      printk("\tLocality Change Int Support\n");
>> +   if (intfcaps & TPM_INTF_STS_VALID_INT)
>> +      printk("\tSts Valid Int Support\n");
>> +   if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
>> +      printk("\tData Avail Int Support\n");
>> +
>> +   /*Interupt setup */
>> +   intmask = ioread32(TPM_INT_ENABLE(tpm, tpm->locality));
>> +
>> +   intmask |= TPM_INTF_CMD_READY_INT
>> +      | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
>> +      | TPM_INTF_STS_VALID_INT;
>> +
>> +   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask);
>> +
>> +   /*If interupts are enabled, handle it */
>> +   if(irq) {
>> +      if(irq != TPM_PROBE_IRQ) {
>> +     tpm->irq = irq;
>> +      } else {
>> +     /*FIXME add irq probing feature later */
>> +     printk("IRQ probing not implemented\n");
>> +      }
>> +   }
>> +
>> +   if(tpm->irq) {
>> +      iowrite8(TPM_INT_VECTOR(tpm, tpm->locality), tpm->irq);
>> +
>> +      if(bind_pirq(tpm->irq, 1, tpm_tis_irq_handler, tpm) != 0) {
>> +     printk("Unabled to request irq: %u for use\n", tpm->irq);
>> +     printk("Will use polling mode\n");
>> +     tpm->irq = 0;
>> +      } else {
>> +     /* Clear all existing */
>> +     iowrite32(TPM_INT_STATUS(tpm, tpm->locality),
>> ioread32(TPM_INT_STATUS(tpm, tpm->locality)));
>> +
>> +     /* Turn on interrupts */
>> +     iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask |
>> TPM_GLOBAL_INT_ENABLE);
>> +      }
>> +   }
>> +
>> +   tpm_get_timeouts(tpm);
>> +   tpm_continue_selftest(tpm);
>> +
>> +
>> +   return tpm;
>> +abort_egress:
>> +   if(tpm != NULL) {
>> +      shutdown_tpm_tis(tpm);
>> +   }
>> +   return NULL;
>> +}
>> +
>> +void shutdown_tpm_tis(struct tpm_chip* tpm){
>> +   int i;
>> +
>> +   printk("Shutting down tpm_tis device\n");
>> +
>> +   iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), ~TPM_GLOBAL_INT_ENABLE);
>> +
>> +   /*Unmap all of the mmio pages */
>> +   for(i = 0; i < 5; ++i) {
>> +      if(tpm->pages[i] != NULL) {
>> +     iounmap(tpm->pages[i], PAGE_SIZE);
>> +     tpm->pages[i] = NULL;
>> +      }
>> +   }
>> +   free(tpm);
>> +   return;
>> +}
>> +
>> +
>> +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen,
>> uint8_t** resp, size_t* resplen)
>> +{
>> +   if(tpm->locality < 0) {
>> +      printk("tpm_tis_cmd() failed! locality not set!\n");
>> +      return -1;
>> +   }
>> +   if(reqlen > TPM_BUFSIZE) {
>> +      reqlen = TPM_BUFSIZE;
>> +   }
>> +   memcpy(tpm->data_buffer, req, reqlen);
>> +   *resplen = tpm_transmit(tpm, tpm->data_buffer, TPM_BUFSIZE);
>> +
>> +   *resp = malloc(*resplen);
>> +   memcpy(*resp, tpm->data_buffer, *resplen);
>> +   return 0;
>> +}
>> +
>> +#ifdef HAVE_LIBC
>> +int tpm_tis_open(struct tpm_chip* tpm)
>> +{
>> +   /* Silently prevent multiple opens */
>> +   if(tpm->fd != -1) {
>> +      return tpm->fd;
>> +   }
>> +
>> +   tpm->fd = alloc_fd(FTYPE_TPM_TIS);
>> +   printk("tpm_tis_open() -> %d\n", tpm->fd);
>> +   files[tpm->fd].tpm_tis.dev = tpm;
>> +   files[tpm->fd].tpm_tis.offset = 0;
>> +   files[tpm->fd].tpm_tis.respgot = 0;
>> +   return tpm->fd;
>> +}
>> +
>> +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count)
>> +{
>> +   struct tpm_chip* tpm;
>> +   tpm = files[fd].tpm_tis.dev;
>> +
>> +   if(tpm->locality < 0) {
>> +      printk("tpm_tis_posix_write() failed! locality not set!\n");
>> +      errno = EINPROGRESS;
>> +      return -1;
>> +   }
>> +   if(count == 0) {
>> +      return 0;
>> +   }
>> +
>> +   /* Return an error if we are already processing a command */
>> +   if(count > TPM_BUFSIZE) {
>> +      count = TPM_BUFSIZE;
>> +   }
>> +   /* Send the command now */
>> +   memcpy(tpm->data_buffer, buf, count);
>> +   if((tpm->data_len = tpm_transmit(tpm, tpm->data_buffer,
>> TPM_BUFSIZE)) < 0) {
>> +      errno = EIO;
>> +      return -1;
>> +   }
>> +   return count;
>> +}
>> +
>> +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count)
>> +{
>> +   int rc;
>> +   struct tpm_chip* tpm;
>> +   tpm = files[fd].tpm_tis.dev;
>> +
>> +   if(count == 0) {
>> +      return 0;
>> +   }
>> +
>> +   /* If there is no tpm resp to read, return EIO */
>> +   if(tpm->data_len < 0) {
>> +      errno = EIO;
>> +      return -1;
>> +   }
>> +
>> +
>> +   /* Handle EOF case */
>> +   if(files[fd].tpm_tis.offset >= tpm->data_len) {
>> +      rc = 0;
>> +   } else {
>> +      rc = min(tpm->data_len - files[fd].tpm_tis.offset, count);
>> +      memcpy(buf, tpm->data_buffer + files[fd].tpm_tis.offset, rc);
>> +   }
>> +   files[fd].tpm_tis.offset += rc;
>> +   /* Reset the data pending flag */
>> +   return rc;
>> +}
>> +int tpm_tis_posix_fstat(int fd, struct stat* buf)
>> +{
>> +   struct tpm_chip* tpm;
>> +   tpm = files[fd].tpm_tis.dev;
>> +
>> +   buf->st_mode = O_RDWR;
>> +   buf->st_uid = 0;
>> +   buf->st_gid = 0;
>> +   buf->st_size = be32_to_cpu(*((uint32_t*)(tpm->data_buffer + 2)));
>> +   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
>> +   return 0;
>> +}
>> +
>> +
>> +#endif
>> diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c
>> --- /dev/null
>> +++ b/extras/mini-os/tpmback.c
>> @@ -0,0 +1,1114 @@
>> +/*
>> + * Copyright (c) 2010-2012 United States Government, as represented by
>> + * the Secretary of Defense.  All rights reserved.
>> + *
>> + * This driver 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, either version 3 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This driver is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Based upon the files:
>> + *  drivers/xen/tpmbk.c
>> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
>> + */
>> +#include <mini-os/os.h>
>> +#include <mini-os/xenbus.h>
>> +#include <mini-os/events.h>
>> +#include <errno.h>
>> +#include <mini-os/gnttab.h>
>> +#include <xen/io/xenbus.h>
>> +#include <xen/io/tpmif.h>
>> +#include <xen/io/protocols.h>
>> +#include <mini-os/xmalloc.h>
>> +#include <time.h>
>> +#include <mini-os/tpmback.h>
>> +#include <mini-os/lib.h>
>> +#include <fcntl.h>
>> +#include <mini-os/mm.h>
>> +#include <mini-os/posix/sys/mman.h>
>> +#include <mini-os/semaphore.h>
>> +#include <mini-os/wait.h>
>> +
>> +
>> +#ifndef HAVE_LIBC
>> +#define strtoul simple_strtoul
>> +#endif
>> +
>> +//#define TPMBACK_PRINT_DEBUG
>> +#ifdef TPMBACK_PRINT_DEBUG
>> +#define TPMBACK_DEBUG(fmt,...) printk("Tpmback:Debug("__FILE__":%d) "
>> fmt, __LINE__, ##__VA_ARGS__)
>> +#define TPMBACK_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
>> +#else
>> +#define TPMBACK_DEBUG(fmt,...)
>> +#endif
>> +#define TPMBACK_ERR(fmt,...) printk("Tpmback:Error " fmt, ##__VA_ARGS__)
>> +#define TPMBACK_LOG(fmt,...) printk("Tpmback:Info " fmt, ##__VA_ARGS__)
>> +
>> +#define min(a,b) (((a) < (b)) ? (a) : (b))
>> +
>> +/* Default size of the tpmif array at initialization */
>> +#define DEF_ARRAY_SIZE 1
>> +
>> +/* tpmif and tpmdev flags */
>> +#define TPMIF_CLOSED 1
>> +#define TPMIF_REQ_READY 2
>> +
>> +struct tpmif {
>> +   domid_t domid;
>> +   unsigned int handle;
>> +
>> +   char* fe_path;
>> +   char* fe_state_path;
>> +
>> +   /* Locally bound event channel*/
>> +   evtchn_port_t evtchn;
>> +
>> +   /* Shared page */
>> +   tpmif_tx_interface_t* tx;
>> +
>> +   /* pointer to TPMIF_RX_RING_SIZE pages */
>> +   void** pages;
>> +
>> +   enum xenbus_state state;
>> +   enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
>> +
>> +   char* uuid;
>> +
>> +   /* state flags */
>> +   int flags;
>> +};
>> +typedef struct tpmif tpmif_t;
>> +
>> +struct tpmback_dev {
>> +
>> +   tpmif_t** tpmlist;
>> +   unsigned long num_tpms;
>> +   unsigned long num_alloc;
>> +
>> +   struct gntmap map;
>> +
>> +   /* True if at least one tpmif has a request to be handled */
>> +   int flags;
>> +
>> +   /* exclusive domains, see init_tpmback comment in tpmback.h */
>> +   char** exclusive_uuids;
>> +
>> +   xenbus_event_queue events;
>> +
>> +   /* Callbacks */
>> +   void (*open_callback)(domid_t, unsigned int);
>> +   void (*close_callback)(domid_t, unsigned int);
>> +   void (*suspend_callback)(domid_t, unsigned int);
>> +   void (*resume_callback)(domid_t, unsigned int);
>> +};
>> +typedef struct tpmback_dev tpmback_dev_t;
>> +
>> +enum { EV_NONE, EV_NEWFE, EV_STCHNG } tpm_ev_enum;
>> +
>> +/* Global objects */
>> +static struct thread* eventthread = NULL;
>> +static tpmback_dev_t gtpmdev = {
>> +   .tpmlist = NULL,
>> +   .num_tpms = 0,
>> +   .num_alloc = 0,
>> +   .flags = TPMIF_CLOSED,
>> +   .events = NULL,
>> +   .open_callback = NULL,
>> +   .close_callback = NULL,
>> +   .suspend_callback = NULL,
>> +   .resume_callback = NULL,
>> +};
>> +struct wait_queue_head waitq;
>> +int globalinit = 0;
>> +
>> +/************************************
>> + * TPMIF SORTED ARRAY FUNCTIONS
>> + * tpmback_dev_t.tpmlist is a sorted array, sorted by domid and then
>> handle number
>> + * Duplicates are not allowed
>> + * **********************************/
>> +
>> +inline void tpmif_req_ready(tpmif_t* tpmif) {
>> +   tpmif->flags |= TPMIF_REQ_READY;
>> +   gtpmdev.flags |= TPMIF_REQ_READY;
>> +}
>> +
>> +inline void tpmdev_check_req(void) {
>> +   int i;
>> +   int flags;
>> +   local_irq_save(flags);
>> +   for(i = 0; i < gtpmdev.num_tpms; ++i) {
>> +      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
>> +     gtpmdev.flags |= TPMIF_REQ_READY;
>> +     local_irq_restore(flags);
>> +     return;
>> +      }
>> +   }
>> +   gtpmdev.flags &= ~TPMIF_REQ_READY;
>> +   local_irq_restore(flags);
>> +}
>> +
>> +inline void tpmif_req_finished(tpmif_t* tpmif) {
>> +   tpmif->flags &= ~TPMIF_REQ_READY;
>> +   tpmdev_check_req();
>> +}
>> +
>> +int __get_tpmif_index(int st, int n, domid_t domid, unsigned int handle)
>> +{
>> +   int i = st + n /2;
>> +   tpmif_t* tmp;
>> +
>> +   if( n <= 0 )
>> +      return -1;
>> +
>> +   tmp = gtpmdev.tpmlist[i];
>> +   if(domid == tmp->domid && tmp->handle == handle) {
>> +      return i;
>> +   } else if ( (domid < tmp->domid) ||
>> +     (domid == tmp->domid && handle < tmp->handle)) {
>> +      return __get_tpmif_index(st, n/2, domid, handle);
>> +   } else {
>> +      return __get_tpmif_index(i + 1, n/2 - ((n +1) % 2), domid, handle);
>> +   }
>> +}
>> +
>> +/* Returns the array index of the tpmif domid/handle. Returns -1 if no
>> such tpmif exists */
>> +int get_tpmif_index(domid_t domid, unsigned int handle)
>> +{
>> +   int flags;
>> +   int index;
>> +   local_irq_save(flags);
>> +   index = __get_tpmif_index(0, gtpmdev.num_tpms, domid, handle);
>> +   local_irq_restore(flags);
>> +   return index;
>> +}
>> +
>> +/* Returns the tpmif domid/handle or NULL if none exists */
>> +tpmif_t* get_tpmif(domid_t domid, unsigned int handle)
>> +{
>> +   int flags;
>> +   int i;
>> +   tpmif_t* ret;
>> +   local_irq_save(flags);
>> +   i = get_tpmif_index(domid, handle);
>> +   if (i < 0) {
>> +      ret = NULL;
>> +   } else {
>> +      ret = gtpmdev.tpmlist[i];
>> +   }
>> +   local_irq_restore(flags);
>> +   return ret;
>> +}
>> +
>> +/* Remove the given tpmif. Returns 0 if it was removed, -1 if it was
>> not removed */
>> +int remove_tpmif(tpmif_t* tpmif)
>> +{
>> +   int i, j;
>> +   char* err;
>> +   int flags;
>> +   local_irq_save(flags);
>> +
>> +   /* Find the index in the array if it exists */
>> +   i = get_tpmif_index(tpmif->domid, tpmif->handle);
>> +   if (i < 0) {
>> +      goto error;
>> +   }
>> +
>> +   /* Remove the interface from the list */
>> +   for(j = i; j < gtpmdev.num_tpms - 1; ++j) {
>> +      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j+1];
>> +   }
>> +   gtpmdev.tpmlist[j] = NULL;
>> +   --gtpmdev.num_tpms;
>> +
>> +   /* If removed tpm was the only ready tpm, then we need to check and
>> turn off the ready flag */
>> +   tpmdev_check_req();
>> +
>> +   local_irq_restore(flags);
>> +
>> +   /* Stop listening for events on this tpm interface */
>> +   if((err = xenbus_unwatch_path_token(XBT_NIL, tpmif->fe_state_path,
>> tpmif->fe_state_path))) {
>> +      TPMBACK_ERR("Unable to unwatch path token `%s' Error was %s
>> Ignoring..\n", tpmif->fe_state_path, err);
>> +      free(err);
>> +   }
>> +
>> +   return 0;
>> +error:
>> +   local_irq_restore(flags);
>> +   return -1;
>> +}
>> +
>> +/* Insert tpmif into dev->tpmlist. Returns 0 on success and non zero on
>> error.
>> + * It is an error to insert a tpmif with the same domid and handle
>> + * number
>> + * as something already in the list */
>> +int insert_tpmif(tpmif_t* tpmif)
>> +{
>> +   int flags;
>> +   unsigned int i, j;
>> +   tpmif_t* tmp;
>> +   char* err;
>> +
>> +   local_irq_save(flags);
>> +
>> +   /*Check if we need to allocate more space */
>> +   if (gtpmdev.num_tpms == gtpmdev.num_alloc) {
>> +      gtpmdev.num_alloc *= 2;
>> +      gtpmdev.tpmlist = realloc(gtpmdev.tpmlist, gtpmdev.num_alloc);
>> +   }
>> +
>> +   /*Find where to put the new interface */
>> +   for(i = 0; i < gtpmdev.num_tpms; ++i)
>> +   {
>> +      tmp = gtpmdev.tpmlist[i];
>> +      if(tpmif->domid == tmp->domid && tpmif->handle == tmp->handle) {
>> +     TPMBACK_ERR("Tried to insert duplicate tpm interface %u/%u\n",
>> (unsigned int) tpmif->domid, tpmif->handle);
>> +     goto error;
>> +      }
>> +      if((tpmif->domid < tmp->domid) ||
>> +        (tpmif->domid == tmp->domid && tpmif->handle < tmp->handle)) {
>> +     break;
>> +      }
>> +   }
>> +
>> +   /*Shift all the tpm pointers past i down one */
>> +   for(j = gtpmdev.num_tpms; j > i; --j) {
>> +      gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j-1];
>> +   }
>> +
>> +   /*Add the new interface */
>> +   gtpmdev.tpmlist[i] = tpmif;
>> +   ++gtpmdev.num_tpms;
>> +
>> +   /*Should not be needed, anything inserted with ready flag is
>> probably an error */
>> +   tpmdev_check_req();
>> +
>> +   local_irq_restore(flags);
>> +
>> +   /*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)))
>> +   {
>> +      /* if we got an error here we should carefully remove the
>> interface and then return */
>> +      TPMBACK_ERR("Unable to watch path token `%s' Error was %s\n",
>> tpmif->fe_state_path, err);
>> +      free(err);
>> +      remove_tpmif(tpmif);
>> +      goto error_post_irq;
>> +   }
>> +
>> +   return 0;
>> +error:
>> +   local_irq_restore(flags);
>> +error_post_irq:
>> +   return -1;
>> +}
>> +
>> +
>> +/*****************
>> + * CHANGE BACKEND STATE
>> + * *****************/
>> +/*Attempts to change the backend state in xenstore
>> + * returns 0 on success and non-zero on error */
>> +int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state)
>> +{
>> +   char path[512];
>> +   char *value;
>> +   char *err;
>> +   enum xenbus_state readst;
>> +   TPMBACK_DEBUG("Backend state change %u/%u from=%d to=%d\n",
>> (unsigned int) tpmif->domid, tpmif->handle, tpmif->state, state);
>> +   if (tpmif->state == state)
>> +      return 0;
>> +
>> +   snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int)
>> tpmif->domid, tpmif->handle);
>> +
>> +   if((err = xenbus_read(XBT_NIL, path, &value))) {
>> +      TPMBACK_ERR("Unable to read backend state %s, error was %s\n",
>> path, err);
>> +      free(err);
>> +      return -1;
>> +   }
>> +   if(sscanf(value, "%d", &readst) != 1) {
>> +      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
>> +      free(value);
>> +      return -1;
>> +   }
>> +   free(value);
>> +
>> +   /* It's possible that the backend state got updated by hotplug or
>> something else behind our back */
>> +   if(readst != tpmif->state) {
>> +      TPMBACK_DEBUG("tpm interface state was %d but xenstore state was
>> %d!\n", tpmif->state, readst);
>> +      tpmif->state = readst;
>> +   }
>> +
>> +   /*If if the state isnt changing, then we dont update xenstore b/c we
>> dont want to fire extraneous events */
>> +   if(tpmif->state == state) {
>> +      return 0;
>> +   }
>> +
>> +   /*update xenstore*/
>> +   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
>> tpmif->domid, tpmif->handle);
>> +   if((err = xenbus_printf(XBT_NIL, path, "state", "%u", state))) {
>> +      TPMBACK_ERR("Error writing to xenstore %s, error was %s new
>> state=%d\n", path, err, state);
>> +      free(err);
>> +      return -1;
>> +   }
>> +
>> +   tpmif->state = state;
>> +
>> +   return 0;
>> +}
>> +/**********************************
>> + * TPMIF CREATION AND DELETION
>> + * *******************************/
>> +inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle)
>> +{
>> +   tpmif_t* tpmif;
>> +   tpmif = malloc(sizeof(*tpmif));
>> +   tpmif->domid = domid;
>> +   tpmif->handle = handle;
>> +   tpmif->fe_path = NULL;
>> +   tpmif->fe_state_path = NULL;
>> +   tpmif->state = XenbusStateInitialising;
>> +   tpmif->status = DISCONNECTED;
>> +   tpmif->tx = NULL;
>> +   tpmif->pages = NULL;
>> +   tpmif->flags = 0;
>> +   tpmif->uuid = NULL;
>> +   return tpmif;
>> +}
>> +
>> +void __free_tpmif(tpmif_t* tpmif)
>> +{
>> +   if(tpmif->pages) {
>> +      free(tpmif->pages);
>> +   }
>> +   if(tpmif->fe_path) {
>> +      free(tpmif->fe_path);
>> +   }
>> +   if(tpmif->fe_state_path) {
>> +      free(tpmif->fe_state_path);
>> +   }
>> +   if(tpmif->uuid) {
>> +      free(tpmif->uuid);
>> +   }
>> +   free(tpmif);
>> +}
>> +/* Creates a new tpm interface, adds it to the sorted array and returns it.
>> + * returns NULL on error
>> + * If the tpm interface already exists, it is returned*/
>> +tpmif_t* new_tpmif(domid_t domid, unsigned int handle)
>> +{
>> +   tpmif_t* tpmif;
>> +   char* err;
>> +   char path[512];
>> +
>> +   /* Make sure we haven't already created this tpm
>> +    * Double events can occur */
>> +   if((tpmif = get_tpmif(domid, handle)) != NULL) {
>> +      return tpmif;
>> +   }
>> +
>> +   tpmif = __init_tpmif(domid, handle);
>> +
>> +   /* Get the uuid from xenstore */
>> +   snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domid,
>> handle);
>> +   if((err = xenbus_read(XBT_NIL, path, &tpmif->uuid))) {
>> +      TPMBACK_ERR("Error reading %s, Error = %s\n", path, err);
>> +      free(err);
>> +      goto error;
>> +   }
>> +
>> +   /* Do the exclusive uuid check now */
>> +   if(gtpmdev.exclusive_uuids != NULL) {
>> +      char** ptr;
>> +
>> +      /* Check that its in the whitelist */
>> +      for(ptr = gtpmdev.exclusive_uuids; *ptr != NULL; ++ptr) {
>> +     if(!strcmp(tpmif->uuid, *ptr)) {
>> +        break;
>> +     }
>> +      }
>> +      /* If *ptr == NULL then we went through the whole list without a
>> match, so close the connection */
>> +      if(*ptr == NULL) {
>> +     tpmif_change_state(tpmif, XenbusStateClosed);
>> +     TPMBACK_ERR("Frontend %u/%u tried to connect with invalid
>> uuid=%s\n", (unsigned int) domid, handle, tpmif->uuid);
>> +     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;
>> +   }
>> +
>> +   snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int)
>> domid, handle);
>> +   if((err = xenbus_read(XBT_NIL, path, &tpmif->fe_path))) {
>> +      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s),
>> Error = %s", path, err);
>> +      free(err);
>> +      goto error;
>> +   }
>> +
>> +   /*Set the state path */
>> +   tpmif->fe_state_path = malloc(strlen(tpmif->fe_path) + 7);
>> +   strcpy(tpmif->fe_state_path, tpmif->fe_path);
>> +   strcat(tpmif->fe_state_path, "/state");
>> +
>> +   if(insert_tpmif(tpmif)) {
>> +      goto error;
>> +   }
>> +   TPMBACK_DEBUG("New tpmif %u/%u\n", (unsigned int) tpmif->domid,
>> tpmif->handle);
>> +   /* Do the callback now */
>> +   if(gtpmdev.open_callback) {
>> +      gtpmdev.open_callback(tpmif->domid, tpmif->handle);
>> +   }
>> +   return tpmif;
>> +error:
>> +   __free_tpmif(tpmif);
>> +   return NULL;
>> +
>> +}
>> +
>> +/* Removes tpmif from dev->tpmlist and frees it's memory usage */
>> +void free_tpmif(tpmif_t* tpmif)
>> +{
>> +   char* err;
>> +   char path[512];
>> +   TPMBACK_DEBUG("Free tpmif %u/%u\n", (unsigned int) tpmif->domid,
>> tpmif->handle);
>> +   if(tpmif->flags & TPMIF_CLOSED) {
>> +      TPMBACK_ERR("Tried to free an instance twice! Theres a bug
>> somewhere!\n");
>> +      BUG();
>> +   }
>> +   tpmif->flags = TPMIF_CLOSED;
>> +
>> +   tpmif_change_state(tpmif, XenbusStateClosing);
>> +
>> +   /* Unmap share page and unbind event channel */
>> +   if(tpmif->status == CONNECTED) {
>> +      tpmif->status = DISCONNECTING;
>> +      mask_evtchn(tpmif->evtchn);
>> +
>> +      if(gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1)) {
>> +     TPMBACK_ERR("%u/%u Error occured while trying to unmap shared
>> page\n", (unsigned int) tpmif->domid, tpmif->handle);
>> +      }
>> +
>> +      unbind_evtchn(tpmif->evtchn);
>> +   }
>> +   tpmif->status = DISCONNECTED;
>> +   tpmif_change_state(tpmif, XenbusStateClosed);
>> +
>> +   /* Do the callback now */
>> +   if(gtpmdev.close_callback) {
>> +      gtpmdev.close_callback(tpmif->domid, tpmif->handle);
>> +   }
>> +
>> +   /* remove from array */
>> +   remove_tpmif(tpmif);
>> +
>> +   /* Wake up anyone possibly waiting on this interface and let them
>> exit */
>> +   wake_up(&waitq);
>> +   schedule();
>> +
>> +   /* Remove the old xenbus entries */
>> +   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
>> tpmif->domid, tpmif->handle);
>> +   if((err = xenbus_rm(XBT_NIL, path))) {
>> +      TPMBACK_ERR("Error cleaning up xenbus entries path=%s
>> error=%s\n", path, err);
>> +      free(err);
>> +   }
>> +
>> +   TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int)
>> tpmif->domid, tpmif->handle);
>> +
>> +   /* free memory */
>> +   __free_tpmif(tpmif);
>> +
>> +}
>> +
>> +/**********************
>> + * REMAINING TPMBACK FUNCTIONS
>> + * ********************/
>> +
>> +/*Event channel handler */
>> +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);
>> +
>> +}
>> +
>> +/* Connect to frontend */
>> +int connect_fe(tpmif_t* tpmif)
>> +{
>> +   char path[512];
>> +   char* err, *value;
>> +   uint32_t domid;
>> +   grant_ref_t ringref;
>> +   evtchn_port_t evtchn;
>> +
>> +   /* If already connected then quit */
>> +   if (tpmif->status == CONNECTED) {
>> +      TPMBACK_DEBUG("%u/%u tried to connect while it was already
>> connected?\n", (unsigned int) tpmif->domid, tpmif->handle);
>> +      return 0;
>> +   }
>> +
>> +   /* Fetch the grant reference */
>> +   snprintf(path, 512, "%s/ring-ref", tpmif->fe_path);
>> +   if((err = xenbus_read(XBT_NIL, path, &value))) {
>> +      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
>> Error = %s", path, err);
>> +      free(err);
>> +      return -1;
>> +   }
>> +   if(sscanf(value, "%d", &ringref) != 1) {
>> +      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
>> +      free(value);
>> +      return -1;
>> +   }
>> +   free(value);
>> +
>> +
>> +   /* Fetch the event channel*/
>> +   snprintf(path, 512, "%s/event-channel", tpmif->fe_path);
>> +   if((err = xenbus_read(XBT_NIL, path, &value))) {
>> +      TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s)
>> Error = %s", path, err);
>> +      free(err);
>> +      return -1;
>> +   }
>> +   if(sscanf(value, "%d", &evtchn) != 1) {
>> +      TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path);
>> +      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) {
>> +      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)))
>> +   {
>> +      TPMBACK_ERR("%u/%u Unable to bind to interdomain event
>> channel!\n", (unsigned int) tpmif->domid, tpmif->handle);
>> +      goto error_post_map;
>> +   }
>> +   unmask_evtchn(tpmif->evtchn);
>> +
>> +   /* Write the ready flag and change status to connected */
>> +   snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int)
>> tpmif->domid, tpmif->handle);
>> +   if((err = xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) {
>> +      TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n",
>> (unsigned int) tpmif->domid, tpmif->handle);
>> +      free(err);
>> +      goto error_post_evtchn;
>> +   }
>> +   tpmif->status = CONNECTED;
>> +   if((tpmif_change_state(tpmif, XenbusStateConnected))){
>> +      goto error_post_evtchn;
>> +   }
>> +
>> +   TPMBACK_LOG("Frontend %u/%u connected\n", (unsigned int)
>> tpmif->domid, tpmif->handle);
>> +
>> +   return 0;
>> +error_post_evtchn:
>> +   mask_evtchn(tpmif->evtchn);
>> +   unbind_evtchn(tpmif->evtchn);
>> +error_post_map:
>> +   gntmap_munmap(&gtpmdev.map, (unsigned long)tpmif->tx, 1);
>> +   return -1;
>> +}
>> +
>> +static int frontend_changed(tpmif_t* tpmif)
>> +{
>> +   int state = xenbus_read_integer(tpmif->fe_state_path);
>> +   if(state < 0) {
>> +      state = XenbusStateUnknown;
>> +   }
>> +
>> +   TPMBACK_DEBUG("Frontend %u/%u state changed to %d\n", (unsigned int)
>> tpmif->domid, tpmif->handle, state);
>> +
>> +   switch (state) {
>> +      case XenbusStateInitialising:
>> +      case XenbusStateInitialised:
>> +     break;
>> +
>> +      case XenbusStateConnected:
>> +     if(connect_fe(tpmif)) {
>> +        TPMBACK_ERR("Failed to connect to front end %u/%u\n", (unsigned
>> int) tpmif->domid, tpmif->handle);
>> +        tpmif_change_state(tpmif, XenbusStateClosed);
>> +        return -1;
>> +     }
>> +     break;
>> +
>> +      case XenbusStateClosing:
>> +     tpmif_change_state(tpmif, XenbusStateClosing);
>> +     break;
>> +
>> +      case XenbusStateUnknown: /* keep it here */
>> +      case XenbusStateClosed:
>> +     free_tpmif(tpmif);
>> +     break;
>> +
>> +      default:
>> +     TPMBACK_DEBUG("BAD STATE CHANGE %u/%u state = %d for tpmif\n",
>> (unsigned int) tpmif->domid, tpmif->handle, state);
>> +     return -1;
>> +   }
>> +   return 0;
>> +}
>> +
>> +
>> +/* parses the string that comes out of xenbus_watch_wait_return. */
>> +static int parse_eventstr(const char* evstr, domid_t* domid, unsigned
>> int* handle)
>> +{
>> +   int ret;
>> +   char cmd[40];
>> +   char* err;
>> +   char* value;
>> +   unsigned int udomid = 0;
>> +   tpmif_t* tpmif;
>> +   /* First check for new frontends, this occurs when
>> /backend/vtpm/<domid>/<handle> gets created. Note we what the sscanf to
>> fail on the last %s */
>> +   if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd)
>> == 2) {
>> +      *domid = udomid;
>> +      /* Make sure the entry exists, if this event triggers because the
>> entry dissapeared then ignore it */
>> +      if((err = xenbus_read(XBT_NIL, evstr, &value))) {
>> +     free(err);
>> +     return EV_NONE;
>> +      }
>> +      free(value);
>> +      /* Make sure the tpmif entry does not already exist, this should
>> not happen */
>> +      if((tpmif = get_tpmif(*domid, *handle)) != NULL) {
>> +     TPMBACK_DEBUG("Duplicate tpm entries! %u %u\n", tpmif->domid,
>> tpmif->handle);
>> +     return EV_NONE;
>> +      }
>> +      return EV_NEWFE;
>> +   } else if((ret = sscanf(evstr,
>> "/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) == 3) {
>> +      *domid = udomid;
>> +      if (!strcmp(cmd, "state"))
>> +     return EV_STCHNG;
>> +   }
>> +   return EV_NONE;
>> +}
>> +
>> +void handle_backend_event(char* evstr) {
>> +   tpmif_t* tpmif;
>> +   domid_t domid;
>> +   unsigned int handle;
>> +   int event;
>> +
>> +   TPMBACK_DEBUG("Xenbus Event: %s\n", evstr);
>> +
>> +   event = parse_eventstr(evstr, &domid, &handle);
>> +
>> +   switch(event) {
>> +      case EV_NEWFE:
>> +     if(new_tpmif(domid, handle) == NULL) {
>> +        TPMBACK_ERR("Failed to create new tpm instance %u/%u\n",
>> (unsigned int) domid, handle);
>> +     }
>> +     wake_up(&waitq);
>> +     break;
>> +      case EV_STCHNG:
>> +     if((tpmif = get_tpmif(domid, handle))) {
>> +        frontend_changed(tpmif);
>> +     } else {
>> +        TPMBACK_DEBUG("Event Received for non-existant tpm!
>> instance=%u/%u xenbus_event=%s\n", (unsigned int) domid, handle, evstr);
>> +     }
>> +     break;
>> +   }
>> +}
>> +
>> +/* Runs through the given path and creates events recursively
>> + * for all of its children.
>> + * @path - xenstore path to scan */
>> +static void generate_backend_events(const char* path)
>> +{
>> +   char* err;
>> +   int i, len;
>> +   char **dirs;
>> +   char *entry;
>> +
>> +   if((err = xenbus_ls(XBT_NIL, path, &dirs)) != NULL) {
>> +      free(err);
>> +      return;
>> +   }
>> +
>> +   for(i = 0; dirs[i] != NULL; ++i) {
>> +      len = strlen(path) + strlen(dirs[i]) + 2;
>> +      entry = malloc(len);
>> +      snprintf(entry, len, "%s/%s", path, dirs[i]);
>> +
>> +      /* Generate and handle event for the entry itself */
>> +      handle_backend_event(entry);
>> +
>> +      /* Do children */
>> +      generate_backend_events(entry);
>> +
>> +      /* Cleanup */
>> +      free(entry);
>> +      free(dirs[i]);
>> +   }
>> +   free(dirs);
>> +   return;
>> +}
>> +
>> +char* tpmback_get_uuid(domid_t domid, unsigned int handle)
>> +{
>> +   tpmif_t* tpmif;
>> +   if((tpmif = get_tpmif(domid, handle)) == NULL) {
>> +      TPMBACK_DEBUG("get_uuid() failed, %u/%u is an invalid
>> frontend\n", (unsigned int) domid, handle);
>> +      return NULL;
>> +   }
>> +
>> +   return tpmif->uuid;
>> +}
>> +
>> +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int))
>> +{
>> +   gtpmdev.open_callback = cb;
>> +}
>> +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int))
>> +{
>> +   gtpmdev.close_callback = cb;
>> +}
>> +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int))
>> +{
>> +   gtpmdev.suspend_callback = cb;
>> +}
>> +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int))
>> +{
>> +   gtpmdev.resume_callback = cb;
>> +}
>> +
>> +static void event_listener(void)
>> +{
>> +   const char* bepath = "backend/vtpm";
>> +   char **path;
>> +   char* err;
>> +
>> +   /* Setup the backend device watch */
>> +   if((err = xenbus_watch_path_token(XBT_NIL, bepath, bepath,
>> &gtpmdev.events)) != NULL) {
>> +      TPMBACK_ERR("xenbus_watch_path_token(%s) failed with error
>> %s!\n", bepath, err);
>> +      free(err);
>> +      goto egress;
>> +   }
>> +
>> +   /* Check for any frontends that connected before we set the watch.
>> +    * This is almost guaranteed to happen if both domains are started
>> +    * immediatly one after the other.
>> +    * We do this by manually generating events on everything in the backend
>> +    * path */
>> +   generate_backend_events(bepath);
>> +
>> +   /* Wait and listen for changes in frontend connections */
>> +   while(1) {
>> +      path = xenbus_wait_for_watch_return(&gtpmdev.events);
>> +
>> +      /*If quit flag was set then exit */
>> +      if(gtpmdev.flags & TPMIF_CLOSED) {
>> +     TPMBACK_DEBUG("listener thread got quit event. Exiting..\n");
>> +     free(path);
>> +     break;
>> +      }
>> +      handle_backend_event(*path);
>> +      free(path);
>> +
>> +   }
>> +
>> +   if((err = xenbus_unwatch_path_token(XBT_NIL, bepath, bepath)) != NULL) {
>> +      free(err);
>> +   }
>> +egress:
>> +   return;
>> +}
>> +
>> +void event_thread(void* p) {
>> +   event_listener();
>> +}
>> +
>> +void init_tpmback(char** exclusive_uuids)
>> +{
>> +   if(!globalinit) {
>> +      init_waitqueue_head(&waitq);
>> +      globalinit = 1;
>> +   }
>> +   printk("============= Init TPM BACK ================\n");
>> +   gtpmdev.tpmlist = malloc(sizeof(tpmif_t*) * DEF_ARRAY_SIZE);
>> +   gtpmdev.num_alloc = DEF_ARRAY_SIZE;
>> +   gtpmdev.num_tpms = 0;
>> +   gtpmdev.flags = 0;
>> +   gtpmdev.exclusive_uuids = exclusive_uuids;
>> +
>> +   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
>> +   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
>> +
>> +   eventthread = create_thread("tpmback-listener", event_thread, NULL);
>> +
>> +}
>> +
>> +void shutdown_tpmback(void)
>> +{
>> +   /* Disable callbacks */
>> +   gtpmdev.open_callback = gtpmdev.close_callback = NULL;
>> +   gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL;
>> +
>> +   TPMBACK_LOG("Shutting down tpm backend\n");
>> +   /* Set the quit flag */
>> +   gtpmdev.flags = TPMIF_CLOSED;
>> +
>> +   //printk("num tpms is %d\n", gtpmdev.num_tpms);
>> +   /*Free all backend instances */
>> +   while(gtpmdev.num_tpms) {
>> +      free_tpmif(gtpmdev.tpmlist[0]);
>> +   }
>> +   free(gtpmdev.tpmlist);
>> +   gtpmdev.tpmlist = NULL;
>> +   gtpmdev.num_alloc = 0;
>> +
>> +   /* Wake up anyone possibly waiting on the device and let them exit */
>> +   wake_up(&waitq);
>> +   schedule();
>> +}
>> +
>> +inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int
>> handle, char* uuid)
>> +{
>> +   tpmcmd->domid = domid;
>> +   tpmcmd->handle = handle;
>> +   tpmcmd->uuid = uuid;
>> +   tpmcmd->req = NULL;
>> +   tpmcmd->req_len = 0;
>> +   tpmcmd->resp = NULL;
>> +   tpmcmd->resp_len = 0;
>> +}
>> +
>> +tpmcmd_t* get_request(tpmif_t* tpmif) {
>> +   tpmcmd_t* cmd;
>> +   tpmif_tx_request_t* tx;
>> +   int offset;
>> +   int tocopy;
>> +   int i;
>> +   uint32_t domid;
>> +   int flags;
>> +
>> +   local_irq_save(flags);
>> +
>> +   /* Allocate the cmd object to hold the data */
>> +   if((cmd = malloc(sizeof(*cmd))) == NULL) {
>> +      goto error;
>> +   }
>> +   init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid);
>> +
>> +   tx = &tpmif->tx->ring[0].req;
>> +   cmd->req_len = tx->size;
>> +   /* 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);
>> +
>> +   }
>> +
>> +#ifdef TPMBACK_PRINT_DEBUG
>> +   TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u",
>> (unsigned int) tpmif->domid, tpmif->handle, cmd->req_len);
>> +   for(i = 0; i < cmd->req_len; ++i) {
>> +      if (!(i % 30)) {
>> +     TPMBACK_DEBUG_MORE("\n");
>> +      }
>> +      TPMBACK_DEBUG_MORE("%02hhX ", cmd->req[i]);
>> +   }
>> +   TPMBACK_DEBUG_MORE("\n\n");
>> +#endif
>> +
>> +   local_irq_restore(flags);
>> +   return cmd;
>> +error:
>> +   if(cmd != NULL) {
>> +      if (cmd->req != NULL) {
>> +     free(cmd->req);
>> +     cmd->req = NULL;
>> +      }
>> +      free(cmd);
>> +      cmd = NULL;
>> +   }
>> +   local_irq_restore(flags);
>> +   return NULL;
>> +
>> +}
>> +
>> +void send_response(tpmcmd_t* cmd, tpmif_t* tpmif)
>> +{
>> +   tpmif_tx_request_t* tx;
>> +   int offset;
>> +   int i;
>> +   uint32_t domid;
>> +   int tocopy;
>> +   int flags;
>> +
>> +   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);
>> +
>> +   }
>> +
>> +#ifdef TPMBACK_PRINT_DEBUG
>> +   TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int)
>> tpmif->domid, tpmif->handle, cmd->resp_len);
>> +   for(i = 0; i < cmd->resp_len; ++i) {
>> +      if (!(i % 30)) {
>> +     TPMBACK_DEBUG_MORE("\n");
>> +      }
>> +      TPMBACK_DEBUG_MORE("%02hhX ", cmd->resp[i]);
>> +   }
>> +   TPMBACK_DEBUG_MORE("\n\n");
>> +#endif
>> +   /* clear the ready flag and send the event channel notice to the
>> frontend */
>> +   tpmif_req_finished(tpmif);
>> +   notify_remote_via_evtchn(tpmif->evtchn);
>> +error:
>> +   local_irq_restore(flags);
>> +   return;
>> +}
>> +
>> +tpmcmd_t* tpmback_req_any(void)
>> +{
>> +   int i;
>> +   /* Block until something has a request */
>> +   wait_event(waitq, (gtpmdev.flags & (TPMIF_REQ_READY | TPMIF_CLOSED)));
>> +
>> +   /* Check if were shutting down */
>> +   if(gtpmdev.flags & TPMIF_CLOSED) {
>> +      /* if something was waiting for us to give up the queue so it can
>> shutdown, let it finish */
>> +      schedule();
>> +      return NULL;
>> +   }
>> +
>> +   for(i = 0; i < gtpmdev.num_tpms; ++i) {
>> +      if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) {
>> +     return get_request(gtpmdev.tpmlist[i]);
>> +      }
>> +   }
>> +
>> +   TPMBACK_ERR("backend request ready flag was set but no interfaces
>> were actually ready\n");
>> +   return NULL;
>> +}
>> +
>> +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle)
>> +{
>> +   tpmif_t* tpmif;
>> +   tpmif = get_tpmif(domid, handle);
>> +   if(tpmif == NULL) {
>> +      return NULL;
>> +   }
>> +
>> +   wait_event(waitq, (tpmif->flags & (TPMIF_REQ_READY | TPMIF_CLOSED)
>> || gtpmdev.flags & TPMIF_CLOSED));
>> +
>> +   /* Check if were shutting down */
>> +   if(tpmif->flags & TPMIF_CLOSED || gtpmdev.flags & TPMIF_CLOSED) {
>> +      /* if something was waiting for us to give up the queue so it can
>> free this instance, let it finish */
>> +      schedule();
>> +      return NULL;
>> +   }
>> +
>> +   return get_request(tpmif);
>> +}
>> +
>> +void tpmback_resp(tpmcmd_t* tpmcmd)
>> +{
>> +   tpmif_t* tpmif;
>> +
>> +   /* Get the associated interface, if it doesnt exist then just quit */
>> +   tpmif = get_tpmif(tpmcmd->domid, tpmcmd->handle);
>> +   if(tpmif == NULL) {
>> +      TPMBACK_ERR("Tried to send a reponse to non existant frontend
>> %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
>> +      goto end;
>> +   }
>> +
>> +   if(!(tpmif->flags & TPMIF_REQ_READY)) {
>> +      TPMBACK_ERR("Tried to send response to a frontend that was not
>> waiting for one %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle);
>> +      goto end;
>> +   }
>> +
>> +   /* Send response to frontend */
>> +   send_response(tpmcmd, tpmif);
>> +
>> +end:
>> +   if(tpmcmd->req != NULL) {
>> +      free(tpmcmd->req);
>> +   }
>> +   free(tpmcmd);
>> +   return;
>> +}
>> +
>> +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int *handle)
>> +{
>> +   tpmif_t* tpmif;
>> +   int flags;
>> +   wait_event(waitq, ((gtpmdev.num_tpms > 0) || gtpmdev.flags &
>> TPMIF_CLOSED));
>> +   if(gtpmdev.flags & TPMIF_CLOSED) {
>> +      return -1;
>> +   }
>> +   local_irq_save(flags);
>> +   tpmif = gtpmdev.tpmlist[0];
>> +   *domid = tpmif->domid;
>> +   *handle = tpmif->handle;
>> +   local_irq_restore(flags);
>> +
>> +   return 0;
>> +}
>> +
>> +int tpmback_num_frontends(void)
>> +{
>> +   return gtpmdev.num_tpms;
>> +}
>> diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c
>> --- /dev/null
>> +++ b/extras/mini-os/tpmfront.c
>> @@ -0,0 +1,606 @@
>> +/*
>> + * Copyright (c) 2010-2012 United States Government, as represented by
>> + * the Secretary of Defense.  All rights reserved.
>> + *
>> + * This driver 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, either version 3 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This driver is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Based upon the files:
>> + *  drivers/char/tpm/tpm_vtpm.c
>> + *  drivers/char/tpm/tpm_xen.c
>> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation
>> + */
>> +#include <mini-os/os.h>
>> +#include <mini-os/xenbus.h>
>> +#include <mini-os/xmalloc.h>
>> +#include <mini-os/events.h>
>> +#include <mini-os/wait.h>
>> +#include <mini-os/gnttab.h>
>> +#include <xen/io/xenbus.h>
>> +#include <xen/io/tpmif.h>
>> +#include <mini-os/tpmfront.h>
>> +#include <fcntl.h>
>> +
>> +//#define TPMFRONT_PRINT_DEBUG
>> +#ifdef TPMFRONT_PRINT_DEBUG
>> +#define TPMFRONT_DEBUG(fmt,...) printk("Tpmfront:Debug("__FILE__":%d) "
>> fmt, __LINE__, ##__VA_ARGS__)
>> +#define TPMFRONT_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__)
>> +#else
>> +#define TPMFRONT_DEBUG(fmt,...)
>> +#endif
>> +#define TPMFRONT_ERR(fmt,...) printk("Tpmfront:Error " fmt, ##__VA_ARGS__)
>> +#define TPMFRONT_LOG(fmt,...) printk("Tpmfront:Info " fmt, ##__VA_ARGS__)
>> +
>> +#define min(a,b) (((a) < (b)) ? (a) : (b))
>> +
>> +void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void
>> *data) {
>> +   struct tpmfront_dev* dev = (struct tpmfront_dev*) data;
>> +   /*If we get a response when we didnt make a request, just ignore it */
>> +   if(!dev->waiting) {
>> +      return;
>> +   }
>> +
>> +   dev->waiting = 0;
>> +#ifdef HAVE_LIBC
>> +   if(dev->fd >= 0) {
>> +      files[dev->fd].read = 1;
>> +   }
>> +#endif
>> +   wake_up(&dev->waitq);
>> +}
>> +
>> +static int publish_xenbus(struct tpmfront_dev* dev) {
>> +   xenbus_transaction_t xbt;
>> +   int retry;
>> +   char* err;
>> +   /* Write the grant reference and event channel to xenstore */
>> +again:
>> +   if((err = xenbus_transaction_start(&xbt))) {
>> +      TPMFRONT_ERR("Unable to start xenbus transaction, error was
>> %s\n", err);
>> +      free(err);
>> +      return -1;
>> +   }
>> +
>> +   if((err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
>> (unsigned int) dev->ring_ref))) {
>> +      TPMFRONT_ERR("Unable to write %s/ring-ref, error was %s\n",
>> dev->nodename, err);
>> +      free(err);
>> +      goto abort_transaction;
>> +   }
>> +
>> +   if((err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
>> (unsigned int) dev->evtchn))) {
>> +      TPMFRONT_ERR("Unable to write %s/event-channel, error was %s\n",
>> dev->nodename, err);
>> +      free(err);
>> +      goto abort_transaction;
>> +   }
>> +
>> +   if((err = xenbus_transaction_end(xbt, 0, &retry))) {
>> +      TPMFRONT_ERR("Unable to complete xenbus transaction, error was
>> %s\n", err);
>> +      free(err);
>> +      return -1;
>> +   }
>> +   if(retry) {
>> +      goto again;
>> +   }
>> +
>> +   return 0;
>> +abort_transaction:
>> +   if((err = xenbus_transaction_end(xbt, 1, &retry))) {
>> +      free(err);
>> +   }
>> +   return -1;
>> +}
>> +
>> +static int wait_for_backend_connect(xenbus_event_queue* events, char* path)
>> +{
>> +   int state;
>> +
>> +   TPMFRONT_LOG("Waiting for backend connection..\n");
>> +   /* Wait for the backend to connect */
>> +   while(1) {
>> +      state = xenbus_read_integer(path);
>> +      if ( state < 0)
>> +     state = XenbusStateUnknown;
>> +      switch(state) {
>> +     /* Bad states, we quit with error */
>> +     case XenbusStateUnknown:
>> +     case XenbusStateClosing:
>> +     case XenbusStateClosed:
>> +        TPMFRONT_ERR("Unable to connect to backend\n");
>> +        return -1;
>> +     /* If backend is connected then break out of loop */
>> +     case XenbusStateConnected:
>> +        TPMFRONT_LOG("Backend Connected\n");
>> +        return 0;
>> +     default:
>> +        xenbus_wait_for_watch(events);
>> +      }
>> +   }
>> +
>> +}
>> +
>> +static int wait_for_backend_closed(xenbus_event_queue* events, char* path)
>> +{
>> +   int state;
>> +
>> +   TPMFRONT_LOG("Waiting for backend to close..\n");
>> +   while(1) {
>> +      state = xenbus_read_integer(path);
>> +      if ( state < 0)
>> +     state = XenbusStateUnknown;
>> +      switch(state) {
>> +     case XenbusStateUnknown:
>> +        TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n");
>> +        return -1;
>> +     case XenbusStateClosed:
>> +        TPMFRONT_LOG("Backend Closed\n");
>> +        return 0;
>> +     default:
>> +        xenbus_wait_for_watch(events);
>> +      }
>> +   }
>> +
>> +}
>> +
>> +static int wait_for_backend_state_changed(struct tpmfront_dev* dev,
>> XenbusState state) {
>> +   char* err;
>> +   int ret = 0;
>> +   xenbus_event_queue events = NULL;
>> +   char path[512];
>> +
>> +   snprintf(path, 512, "%s/state", dev->bepath);
>> +   /*Setup the watch to wait for the backend */
>> +   if((err = xenbus_watch_path_token(XBT_NIL, path, path, &events))) {
>> +      TPMFRONT_ERR("Could not set a watch on %s, error was %s\n", path,
>> err);
>> +      free(err);
>> +      return -1;
>> +   }
>> +
>> +   /* Do the actual wait loop now */
>> +   switch(state) {
>> +      case XenbusStateConnected:
>> +     ret = wait_for_backend_connect(&events, path);
>> +     break;
>> +      case XenbusStateClosed:
>> +     ret = wait_for_backend_closed(&events, path);
>> +     break;
>> +      default:
>> +     break;
>> +   }
>> +
>> +   if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) {
>> +      TPMFRONT_ERR("Unable to unwatch %s, error was %s, ignoring..\n",
>> path, err);
>> +      free(err);
>> +   }
>> +   return ret;
>> +}
>> +
>> +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) {
>> +      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);
>> +   TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref);
>> +
>> +   /*Create event channel */
>> +   if(evtchn_alloc_unbound(dev->bedomid, tpmfront_handler, dev,
>> &dev->evtchn)) {
>> +      TPMFRONT_ERR("Unable to allocate event channel\n");
>> +      goto error_postmap;
>> +   }
>> +   unmask_evtchn(dev->evtchn);
>> +   TPMFRONT_DEBUG("event channel is %lu\n", (unsigned long) dev->evtchn);
>> +
>> +   /* Write the entries to xenstore */
>> +   if(publish_xenbus(dev)) {
>> +      goto error_postevtchn;
>> +   }
>> +
>> +   /* Change state to connected */
>> +   dev->state = XenbusStateConnected;
>> +
>> +   /* Tell the backend that we are ready */
>> +   if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
>> dev->state))) {
>> +      TPMFRONT_ERR("Unable to write to xenstore %s/state, value=%u",
>> dev->nodename, XenbusStateConnected);
>> +      free(err);
>> +      goto error;
>> +   }
>> +
>> +   return 0;
>> +error_postevtchn:
>> +      mask_evtchn(dev->evtchn);
>> +      unbind_evtchn(dev->evtchn);
>> +error_postmap:
>> +      gnttab_end_access(dev->ring_ref);
>> +      free_page(dev->tx);
>> +error:
>> +   return -1;
>> +}
>> +
>> +struct tpmfront_dev* init_tpmfront(const char* _nodename)
>> +{
>> +   struct tpmfront_dev* dev;
>> +   const char* nodename;
>> +   char path[512];
>> +   char* value, *err;
>> +   unsigned long long ival;
>> +   int i;
>> +
>> +   printk("============= Init TPM Front ================\n");
>> +
>> +   dev = malloc(sizeof(struct tpmfront_dev));
>> +   memset(dev, 0, sizeof(struct tpmfront_dev));
>> +
>> +#ifdef HAVE_LIBC
>> +   dev->fd = -1;
>> +#endif
>> +
>> +   nodename = _nodename ? _nodename : "device/vtpm/0";
>> +   dev->nodename = strdup(nodename);
>> +
>> +   init_waitqueue_head(&dev->waitq);
>> +
>> +   /* Get backend domid */
>> +   snprintf(path, 512, "%s/backend-id", dev->nodename);
>> +   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;
>> +   }
>> +   if(sscanf(value, "%llu", &ival) != 1) {
>> +      TPMFRONT_ERR("%s has non-integer value (%s)\n", path, value);
>> +      free(value);
>> +      goto error;
>> +   }
>> +   free(value);
>> +   dev->bedomid = ival;
>> +
>> +   /* Get backend xenstore path */
>> +   snprintf(path, 512, "%s/backend", dev->nodename);
>> +   if((err = xenbus_read(XBT_NIL, path, &dev->bepath))) {
>> +      TPMFRONT_ERR("Unable to read %s during tpmfront initialization!
>> error = %s\n", path, err);
>> +      free(err);
>> +      goto error;
>> +   }
>> +
>> +   /* Create and publish grant reference and event channel */
>> +   if (tpmfront_connect(dev)) {
>> +      goto error;
>> +   }
>> +
>> +   /* Wait for backend to connect */
>> +   if( wait_for_backend_state_changed(dev, XenbusStateConnected)) {
>> +      goto error;
>> +   }
>> +
>> +   /* Allocate pages that will contain the messages */
>> +   dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE);
>> +   if(dev->pages == NULL) {
>> +      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;
>> +      }
>> +   }
>> +
>> +   TPMFRONT_LOG("Initialization Completed successfully\n");
>> +
>> +   return dev;
>> +
>> +error:
>> +   shutdown_tpmfront(dev);
>> +   return NULL;
>> +}
>> +void shutdown_tpmfront(struct tpmfront_dev* dev)
>> +{
>> +   char* err;
>> +   char path[512];
>> +   int i;
>> +   tpmif_tx_request_t* tx;
>> +   if(dev == NULL) {
>> +      return;
>> +   }
>> +   TPMFRONT_LOG("Shutting down tpmfront\n");
>> +   /* disconnect */
>> +   if(dev->state == XenbusStateConnected) {
>> +      dev->state = XenbusStateClosing;
>> +      //FIXME: Transaction for this?
>> +      /* Tell backend we are closing */
>> +      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
>> (unsigned int) dev->state))) {
>> +     free(err);
>> +      }
>> +
>> +      /* Clean up xenstore entries */
>> +      snprintf(path, 512, "%s/event-channel", dev->nodename);
>> +      if((err = xenbus_rm(XBT_NIL, path))) {
>> +     free(err);
>> +      }
>> +      snprintf(path, 512, "%s/ring-ref", dev->nodename);
>> +      if((err = xenbus_rm(XBT_NIL, path))) {
>> +     free(err);
>> +      }
>> +
>> +      /* Tell backend we are closed */
>> +      dev->state = XenbusStateClosed;
>> +      if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u",
>> (unsigned int) dev->state))) {
>> +     TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename,
>> err);
>> +     free(err);
>> +      }
>> +
>> +      /* 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);
>> +
>> +   }
>> +
>> +   /* Cleanup memory usage */
>> +   if(dev->respbuf) {
>> +      free(dev->respbuf);
>> +   }
>> +   if(dev->bepath) {
>> +      free(dev->bepath);
>> +   }
>> +   if(dev->nodename) {
>> +      free(dev->nodename);
>> +   }
>> +   free(dev);
>> +}
>> +
>> +int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t
>> length)
>> +{
>> +   int i;
>> +   tpmif_tx_request_t* tx = NULL;
>> +   /* Error Checking */
>> +   if(dev == NULL || dev->state != XenbusStateConnected) {
>> +      TPMFRONT_ERR("Tried to send message through disconnected
>> frontend\n");
>> +      return -1;
>> +   }
>> +
>> +#ifdef TPMFRONT_PRINT_DEBUG
>> +   TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length);
>> +   for(i = 0; i < length; ++i) {
>> +      if(!(i % 30)) {
>> +     TPMFRONT_DEBUG_MORE("\n");
>> +      }
>> +      TPMFRONT_DEBUG_MORE("%02X ", msg[i]);
>> +   }
>> +   TPMFRONT_DEBUG_MORE("\n");
>> +#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;
>> +   }
>> +   dev->waiting = 1;
>> +   dev->resplen = 0;
>> +#ifdef HAVE_LIBC
>> +   if(dev->fd >= 0) {
>> +      files[dev->fd].read = 0;
>> +      files[dev->fd].tpmfront.respgot = 0;
>> +      files[dev->fd].tpmfront.offset = 0;
>> +   }
>> +#endif
>> +   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;
>> +   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));
>> +
>> +   /* Initialize */
>> +   *msg = NULL;
>> +   *length = 0;
>> +
>> +   /* 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;
>> +   }
>> +   /* 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;
>> +   }
>> +#ifdef TPMFRONT_PRINT_DEBUG
>> +   TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned
>> int) *length);
>> +   for(i = 0; i < *length; ++i) {
>> +      if(!(i % 30)) {
>> +     TPMFRONT_DEBUG_MORE("\n");
>> +      }
>> +      TPMFRONT_DEBUG_MORE("%02X ", (*msg)[i]);
>> +   }
>> +   TPMFRONT_DEBUG_MORE("\n");
>> +#endif
>> +#ifdef HAVE_LIBC
>> +   if(dev->fd >= 0) {
>> +      files[dev->fd].tpmfront.respgot = 1;
>> +   }
>> +#endif
>> +quit:
>> +   return 0;
>> +}
>> +
>> +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen,
>> uint8_t** resp, size_t* resplen)
>> +{
>> +   int rc;
>> +   if((rc = tpmfront_send(dev, req, reqlen))) {
>> +      return rc;
>> +   }
>> +   if((rc = tpmfront_recv(dev, resp, resplen))) {
>> +      return rc;
>> +   }
>> +
>> +   return 0;
>> +}
>> +
>> +#ifdef HAVE_LIBC
>> +#include <errno.h>
>> +int tpmfront_open(struct tpmfront_dev* dev)
>> +{
>> +   /* Silently prevent multiple opens */
>> +   if(dev->fd != -1) {
>> +      return dev->fd;
>> +   }
>> +
>> +   dev->fd = alloc_fd(FTYPE_TPMFRONT);
>> +   printk("tpmfront_open(%s) -> %d\n", dev->nodename, dev->fd);
>> +   files[dev->fd].tpmfront.dev = dev;
>> +   files[dev->fd].tpmfront.offset = 0;
>> +   files[dev->fd].tpmfront.respgot = 0;
>> +   return dev->fd;
>> +}
>> +
>> +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count)
>> +{
>> +   int rc;
>> +   struct tpmfront_dev* dev;
>> +   dev = files[fd].tpmfront.dev;
>> +
>> +   if(count == 0) {
>> +      return 0;
>> +   }
>> +
>> +   /* Return an error if we are already processing a command */
>> +   if(dev->waiting) {
>> +      errno = EINPROGRESS;
>> +      return -1;
>> +   }
>> +   /* Send the command now */
>> +   if((rc = tpmfront_send(dev, buf, count)) != 0) {
>> +      errno = EIO;
>> +      return -1;
>> +   }
>> +   return count;
>> +}
>> +
>> +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count)
>> +{
>> +   int rc;
>> +   uint8_t* dummybuf;
>> +   size_t dummysz;
>> +   struct tpmfront_dev* dev;
>> +
>> +   dev = files[fd].tpmfront.dev;
>> +
>> +   if(count == 0) {
>> +      return 0;
>> +   }
>> +
>> +   /* get the response if we haven't already */
>> +   if(files[dev->fd].tpmfront.respgot == 0) {
>> +      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
>> +     errno = EIO;
>> +     return -1;
>> +      }
>> +   }
>> +
>> +   /* handle EOF case */
>> +   if(files[dev->fd].tpmfront.offset >= dev->resplen) {
>> +      return 0;
>> +   }
>> +
>> +   /* Compute the number of bytes and do the copy operation */
>> +   if((rc = min(count, dev->resplen - files[dev->fd].tpmfront.offset))
>> != 0) {
>> +      memcpy(buf, dev->respbuf + files[dev->fd].tpmfront.offset, rc);
>> +      files[dev->fd].tpmfront.offset += rc;
>> +   }
>> +
>> +   return rc;
>> +}
>> +
>> +int tpmfront_posix_fstat(int fd, struct stat* buf)
>> +{
>> +   uint8_t* dummybuf;
>> +   size_t dummysz;
>> +   int rc;
>> +   struct tpmfront_dev* dev = files[fd].tpmfront.dev;
>> +
>> +   /* If we have a response waiting, then read it now from the backend
>> +    * so we can get its length*/
>> +   if(dev->waiting || (files[dev->fd].read == 1 &&
>> !files[dev->fd].tpmfront.respgot)) {
>> +      if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) {
>> +     errno = EIO;
>> +     return -1;
>> +      }
>> +   }
>> +
>> +   buf->st_mode = O_RDWR;
>> +   buf->st_uid = 0;
>> +   buf->st_gid = 0;
>> +   buf->st_size = dev->resplen;
>> +   buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
>> +
>> +   return 0;
>> +}
>> +
>> +
>> +#endif
>> --
>> 1.7.4.4
>>
>>
>>
>> _______________________________________________
>> Xen-devel mailing list
>> Xen-devel@lists.xen.org
>> http://lists.xen.org/xen-devel
>>



[-- Attachment #1.2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 1459 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

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

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-26 13:30     ` George Dunlap
@ 2012-09-26 14:31       ` Matthew Fioravante
  2012-09-26 21:43       ` Samuel Thibault
  1 sibling, 0 replies; 10+ messages in thread
From: Matthew Fioravante @ 2012-09-26 14:31 UTC (permalink / raw)
  To: George Dunlap; +Cc: Samuel Thibault, xen-devel, Ian Campbell


[-- Attachment #1.1: Type: text/plain, Size: 1002 bytes --]

On 09/26/2012 09:30 AM, George Dunlap wrote:
> On Tue, Sep 18, 2012 at 7:24 PM, Matthew Fioravante
> <matthew.fioravante@jhuapl.edu> wrote:
>> Is there anyone on the dev list that is familiar enough to review it?
>>
>> I can tell you we have been using all 3 of these drivers internally for
>> about 2 years now without issue. All of them are basically ports of the
>> linux drivers to mini-os.
> If you're willing to be the TPM maintainer (which would involve adding
> your name to the MAINTAINERS file), and if Samuel is OK with you
> owning the tpm-related files in stubdom, I think it wouldn't
> necessarily need a thorough review to get in, as long as people are
> happy with how it integrates with the rest of the code.  What do
> people think?
>
>  -George
Looking into the maintainer question now. I'll get back to you all on this.
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel



[-- Attachment #1.2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 1459 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

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

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

* Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os
  2012-09-26 13:30     ` George Dunlap
  2012-09-26 14:31       ` Matthew Fioravante
@ 2012-09-26 21:43       ` Samuel Thibault
  1 sibling, 0 replies; 10+ messages in thread
From: Samuel Thibault @ 2012-09-26 21:43 UTC (permalink / raw)
  To: George Dunlap; +Cc: Matthew Fioravante, xen-devel, Ian Campbell

George Dunlap, le Wed 26 Sep 2012 14:30:23 +0100, a écrit :
> On Tue, Sep 18, 2012 at 7:24 PM, Matthew Fioravante
> <matthew.fioravante@jhuapl.edu> wrote:
> > Is there anyone on the dev list that is familiar enough to review it?
> >
> > I can tell you we have been using all 3 of these drivers internally for
> > about 2 years now without issue. All of them are basically ports of the
> > linux drivers to mini-os.
> 
> If you're willing to be the TPM maintainer (which would involve adding
> your name to the MAINTAINERS file), and if Samuel is OK with you
> owning the tpm-related files in stubdom, I think it wouldn't
> necessarily need a thorough review to get in, as long as people are
> happy with how it integrates with the rest of the code.  What do
> people think?

I'm completely fine with it.

Samuel

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

end of thread, other threads:[~2012-09-26 21:43 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-17 22:08 [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os Matthew Fioravante
2012-09-17 22:52 ` Samuel Thibault
2012-09-18 18:24   ` Matthew Fioravante
2012-09-26 13:30     ` George Dunlap
2012-09-26 14:31       ` Matthew Fioravante
2012-09-26 21:43       ` Samuel Thibault
2012-09-19 12:07 ` Ian Campbell
2012-09-19 14:54   ` Matthew Fioravante
2012-09-26 13:25 ` George Dunlap
2012-09-26 14:29   ` Matthew Fioravante

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.