Index: qemu-git/hw/tpm_tis.h
===================================================================
--- qemu-git.orig/hw/tpm_tis.h
+++ qemu-git/hw/tpm_tis.h
@@ -137,4 +137,21 @@ static inline void dumpBuffer(FILE *stre
     fprintf(stream, "\n");
 }
 
+static inline void clear_sized_buffer(TPMSizedBuffer *tpmsb)
+{
+    if (tpmsb->buffer) {
+       tpmsb->size = 0;
+       qemu_free(tpmsb->buffer);
+       tpmsb->buffer = NULL;
+    }
+}
+
+static inline void set_sized_buffer(TPMSizedBuffer *tpmsb,
+                                    uint8_t *buffer, uint32_t size)
+{
+    clear_sized_buffer(tpmsb);
+    tpmsb->size = size;
+    tpmsb->buffer = buffer;
+}
+
 #endif /* _HW_TPM_TIS_H */
Index: qemu-git/hw/tpm_builtin.c
===================================================================
--- qemu-git.orig/hw/tpm_builtin.c
+++ qemu-git/hw/tpm_builtin.c
@@ -1,4 +1,5 @@
 /*
+ *  built-in TPM support using libtpms
  *
  *  Copyright (c) 2010, 2011 IBM Corporation
  *  Copyright (c) 2010, 2011 Stefan Berger
@@ -17,15 +18,32 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>
  */
 
+#include "blockdev.h"
+#include "block_int.h"
 #include "qemu-common.h"
 #include "hw/hw.h"
 #include "hw/tpm_tis.h"
 #include "hw/pc.h"
 
+#include <libtpms/tpm_library.h>
+#include <libtpms/tpm_error.h>
+#include <libtpms/tpm_memory.h>
+#include <libtpms/tpm_nvfilename.h>
+#include <libtpms/tpm_tis.h>
+
+#include <zlib.h>
+
+
+/* following define will be removed once SeaBIOS has TPM support */
+
 //#define DEBUG_TPM
 //#define DEBUG_TPM_SR /* suspend - resume */
 
 
+#define SAVESTATE_TYPE 'S'
+#define PERMSTATE_TYPE 'P'
+#define VOLASTATE_TYPE 'V'
+
 /* data structures */
 
 typedef struct ThreadParams {
@@ -40,11 +58,17 @@ typedef struct ThreadParams {
 static QemuThread thread;
 
 static QemuMutex state_mutex; /* protects *_state below */
+static QemuCond bs_write_result_cond;
+static TPMSizedBuffer permanent_state = { .size = 0, .buffer = NULL, };
+static TPMSizedBuffer volatile_state  = { .size = 0, .buffer = NULL, };
+static TPMSizedBuffer save_state      = { .size = 0, .buffer = NULL, };
+static int pipefd[2] =  {-1, -1};
 
 static bool thread_terminate = false;
 static bool tpm_initialized = false;
 static bool had_fatal_error = false;
 static bool had_startup_error = false;
+static bool need_read_volatile = false;
 
 static ThreadParams tpm_thread_params;
 
@@ -58,12 +82,54 @@ static const unsigned char tpm_std_fatal
 static char dev_description[80];
 
 
+static int tpmlib_get_prop(enum TPMLIB_TPMProperty prop)
+{
+    int result;
+
+    TPM_RESULT res = TPMLIB_GetTPMProperty(prop, &result);
+
+    assert(res == TPM_SUCCESS);
+
+    return result;
+}
+
+
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+static unsigned int memsum(const unsigned char *buf, int len)
+{
+     int res = 0, i;
+
+     for (i = 0; i < len; i++) {
+          res += buf[i];
+     }
+
+     return res;
+}
+#endif
+
+
 /**
  * Start the TPM. If it had been started before, then terminate and start
  * it again.
  */
 static int startup_tpm(void)
 {
+    TPM_RESULT res;
+
+    if (tpm_initialized) {
+        TPMLIB_Terminate();
+        tpm_initialized = false;
+    }
+
+    res = TPMLIB_MainInit();
+    if (res != TPM_SUCCESS) {
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+        fprintf(stderr,"tpm: Error: Call to TPMLIB_MainInit() failed (rc=%d)\n",
+                       res);
+#endif
+        return 1;
+    }
+
     tpm_initialized = true;
 
 #if defined DEBUG_TPM || defined DEBUG_TPM_SR
@@ -84,6 +150,13 @@ static int late_startup_tpm(void)
 {
     int rc;
 
+    if (startup_bs(bs)) {
+        had_fatal_error = 1;
+        return 1;
+    }
+
+    load_tpm_state_from_bs(bs);
+
     rc  = startup_tpm();
     if (rc) {
         had_fatal_error = 1;
@@ -107,6 +180,7 @@ static void terminate_tpm_thread(void)
         memset(&thread, 0, sizeof(thread));
 
         if (tpm_initialized) {
+            TPMLIB_Terminate();
             tpm_initialized = false;
         }
     }
@@ -116,15 +190,21 @@ static void terminate_tpm_thread(void)
 static void tpm_atexit(void)
 {
     terminate_tpm_thread();
+
+    close(pipefd[0]);
+    pipefd[0] = -1;
+
+    close(pipefd[1]);
+    pipefd[1] = -1;
 }
 
 
 static void *mainLoop(void *d)
 {
-    int res = 0;
     ThreadParams *tParams = (ThreadParams *)d;
     uint32_t in_len, out_len;
     uint8_t *in, *out;
+    TPM_RESULT res;
     uint32_t resp_size; /* total length of response */
 
     /* start command processing */
@@ -176,15 +256,15 @@ static void *mainLoop(void *d)
 
                 resp_size = 0;
 
+                /* TPMLIB_Process may realloc the response buffer */
+                res = TPMLIB_Process(
+                    &tParams->tpm_state->loc[g_locty].r_buffer.buffer,
+                    &resp_size, &out_len,
+                    in, in_len);
 
-                // !!! Send command to TPM & wait for response
-
-
-                if (res != 0) {
+                if (res != TPM_SUCCESS) {
 #ifdef DEBUG_TPM
-                    fprintf(stderr,
-                            "Sending/receiving TPM request/response "
-                            "failed\n");
+                    fprintf(stderr,"TPMLIB_Process() failed\n");
 #endif
                     had_fatal_error = 1;
                 }
@@ -200,7 +280,9 @@ static void *mainLoop(void *d)
             }
 #ifdef DEBUG_TPM
             fprintf(stderr,"sending %d bytes to VM\n", resp_size);
-            dumpBuffer(stdout, out, resp_size);
+            dumpBuffer(stdout,
+                       tParams->tpm_state->loc[g_locty].r_buffer.buffer,
+                       resp_size);
 #endif
             tParams->recv_data_callback(tParams->tpm_state, g_locty);
         } while (in_len > 0);
@@ -210,6 +292,203 @@ static void *mainLoop(void *d)
 }
 
 
+/*****************************************************************
+ * call back functions for the libtpms TPM library
+ ****************************************************************/
+static TPM_RESULT tpm_nvram_init(void)
+{
+    return TPM_SUCCESS;
+}
+
+
+static TPM_RESULT tpm_nvram_loaddata(unsigned char **data,
+                                   uint32_t *length,
+                                   size_t tpm_number __attribute__((unused)),
+                                   const char *name)
+{
+    TPM_RESULT rc = TPM_SUCCESS;
+
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+    fprintf(stderr,"tpm: TPM_NVRAM_LoadData: tpm_number = %d, name = %s\n",
+                   (int)tpm_number, name);
+#endif
+    *length = 0;
+
+    if (!strcmp(name, TPM_PERMANENT_ALL_NAME)) {
+        *length = permanent_state.size;
+
+        if (*length == 0) {
+            rc = TPM_RETRY;
+        } else {
+            /*
+             * keep the permanent state for
+             * as long as possible. We may
+             * be in a resume operation and only
+             * get the volatile state later on when
+             * Qemu provides the state.
+             * Once the volatile state is there,
+             * we can discard the permanent state,
+             * otherwise the perment state will be
+             * discarded in other places
+             */
+            if (volatile_state.size == 0) {
+                rc = TPM_Malloc(data, *length);
+                if (rc == 0)
+                    memcpy(*data, permanent_state.buffer, *length);
+            } else {
+                *data = permanent_state.buffer;
+
+                permanent_state.size = 0;
+                permanent_state.buffer = NULL;
+            }
+        }
+    } else if (!strcmp(name, TPM_VOLATILESTATE_NAME)) {
+        *length = volatile_state.size;
+        if (*length == 0) {
+            rc = TPM_RETRY;
+        } else {
+            *data = volatile_state.buffer;
+
+            volatile_state.size = 0;
+            volatile_state.buffer = NULL;
+        }
+    } else if (!strcmp(name, TPM_SAVESTATE_NAME)) {
+        *length = save_state.size;
+        if (*length == 0) {
+            rc = TPM_RETRY;
+        } else {
+            *data = save_state.buffer;
+            save_state.size = 0;
+            save_state.buffer = NULL;
+        }
+    }
+
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+    fprintf(stderr, "tpm: Read %d bytes of state [sum=%08x]; rc = %d\n",
+            *length, memsum(*data, *length), rc);
+#endif
+
+    return rc;
+}
+
+
+/*
+ * Called by the TPM when permanent data, savestate or volatile state
+ * is updated or needs to be saved.
+ * Primarily we care about savestate and permanent data here.
+ */
+static TPM_RESULT tpm_nvram_storedata(const unsigned char *data,
+                                   uint32_t length,
+                                   size_t tpm_number __attribute__((unused)),
+                                   const char *name)
+{
+    TPM_RESULT rc = TPM_SUCCESS;
+    char what;
+    TPMSizedBuffer *tsb = NULL;
+
+    if (!strcmp(name, TPM_PERMANENT_ALL_NAME)) {
+        tsb = &permanent_state;
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+        fprintf(stderr,"tpm: STORING %5d BYTES OF PERMANENT ALL  [sum=%08x]\n",
+                length, memsum(data, length));
+#endif
+        what = PERMSTATE_TYPE;
+    } else if (!strcmp(name, TPM_SAVESTATE_NAME)) {
+        tsb = &save_state;
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+        fprintf(stderr,"tpm: STORING %5d BYTES OF SAVESTATE      [sum=%08x]\n",
+                length, memsum(data, length));
+#endif
+        what = SAVESTATE_TYPE;
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+    } else if (!strcmp(name, TPM_VOLATILESTATE_NAME)) {
+        fprintf(stderr,"tpm: GOT     %5d BYTES OF VOLATILE STATE [sum=%08x]\n",
+                length, memsum(data, length));
+#endif
+    }
+
+    if (tsb) {
+        /* we may get called here during TPMLIB_MainInit() rather than
+           while running as a thread. Skip writing the state until we
+           process the first command. */
+        qemu_mutex_lock(&state_mutex);
+
+        set_sized_buffer(tsb, (unsigned char *)data, length);
+
+        if (request_sync_to_bs(what)) {
+            rc = TPM_FAIL;
+        }
+
+        /* TPM library will free */
+        tsb->size = 0;
+        tsb->buffer = NULL;
+
+        qemu_mutex_unlock(&state_mutex);
+    }
+
+    if (had_fatal_error) {
+        rc = TPM_FAIL;
+    }
+
+    return rc;
+}
+
+
+static TPM_RESULT tpm_nvram_deletename(
+                                  size_t tpm_number __attribute__((unused)),
+                                  const char *name,
+                                  TPM_BOOL mustExist)
+{
+    TPM_RESULT rc = TPM_SUCCESS;
+
+    /* only handle the savestate here */
+    if (!strcmp(name, TPM_SAVESTATE_NAME)) {
+        qemu_mutex_lock(&state_mutex);
+
+        clear_sized_buffer(&save_state);
+
+        if (request_sync_to_bs(SAVESTATE_TYPE)) {
+            rc = TPM_FAIL;
+        }
+
+        qemu_mutex_unlock(&state_mutex);
+    } else if (!strcmp(name, TPM_VOLATILESTATE_NAME)) {
+        qemu_mutex_lock(&state_mutex);
+
+        clear_sized_buffer(&volatile_state);
+
+        if (request_sync_to_bs(VOLASTATE_TYPE)) {
+            rc = TPM_FAIL;
+        }
+
+        qemu_mutex_unlock(&state_mutex);
+    }
+
+    return rc;
+}
+
+
+static TPM_RESULT tpm_io_init(void)
+{
+    return TPM_SUCCESS;
+}
+
+
+static TPM_RESULT tpm_io_getlocality(TPM_MODIFIER_INDICATOR *localityModifier)
+{
+    *localityModifier = (TPM_MODIFIER_INDICATOR)g_locty;
+
+    return TPM_SUCCESS;
+}
+
+
+static TPM_RESULT tpm_io_getphysicalpresence(TPM_BOOL *physicalPresence)
+{
+    *physicalPresence = FALSE;
+
+    return TPM_SUCCESS;
+}
+
 
 /*****************************************************************/
 
@@ -229,8 +508,12 @@ static void reset(void)
         terminate_tpm_thread();
     }
 
+    clear_sized_buffer(&permanent_state);
+    clear_sized_buffer(&save_state);
+    clear_sized_buffer(&volatile_state);
     had_fatal_error = false;
     thread_terminate = false;
+    need_read_volatile = false;
     had_startup_error = false;
 
     qemu_thread_create(&thread, mainLoop, &tpm_thread_params);
@@ -261,32 +544,92 @@ static int instantiate_with_volatile_dat
 #ifdef DEBUG_TPM_SR
         fprintf(stderr,"tpm: This is resume of a SNAPSHOT?!\n");
 #endif
-        // !!! Xen does not support this ...
         tis_reset_for_snapshot_resume(s);
     }
 
+    /* we need to defer the read since we will not have the encryption key
+       in case storage is encrypted at this point */
+    need_read_volatile = true;
+
     return 0;
 }
 
 
+struct libtpms_callbacks callbacks = {
+    .sizeOfStruct               = sizeof(struct libtpms_callbacks),
+    .tpm_nvram_init             = tpm_nvram_init,
+    .tpm_nvram_loaddata         = tpm_nvram_loaddata,
+    .tpm_nvram_storedata        = tpm_nvram_storedata,
+    .tpm_nvram_deletename       = tpm_nvram_deletename,
+    .tpm_io_init                = tpm_io_init,
+    .tpm_io_getlocality         = tpm_io_getlocality,
+    .tpm_io_getphysicalpresence = tpm_io_getphysicalpresence,
+};
+
+
 static int init(TPMState *s, TPMRecvDataCB *recv_data_cb)
 {
+    int flags;
+
+    bs = bdrv_find("vtpm-nvram");
+    if (bs == NULL) {
+        fprintf(stderr, "The vtpm-nvram driver was not found.\n");
+        goto err_exit;
+    }
+
+    if (TPMLIB_RegisterCallbacks(&callbacks) != TPM_SUCCESS) {
+        goto err_exit;
+    }
+
+    if (check_bs(bs)) {
+        goto err_exit;
+    }
+
     tpm_thread_params.tpm_state = s;
     tpm_thread_params.recv_data_callback = recv_data_cb;
 
     qemu_mutex_init(&state_mutex);
+    qemu_cond_init(&bs_write_result_cond);
 
-    // !!! Do necessary initialization here
+    if (pipe(pipefd)) {
+        goto err_exit;
+    }
+
+    flags = fcntl(pipefd[0], F_GETFL);
+    if (flags < 0) {
+        goto err_exit_close_pipe;
+    }
+
+    if (fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK ) < 0) {
+        goto err_exit_close_pipe;
+    }
+
+    qemu_set_fd_handler(pipefd[0], fulfill_sync_to_bs_request, NULL, NULL);
 
     atexit(tpm_atexit);
 
     return 0;
+
+err_exit_close_pipe:
+    close(pipefd[0]);
+    pipefd[0] = -1;
+    close(pipefd[1]);
+    pipefd[1] = -1;
+
+err_exit:
+    return 1;
 }
 
 
 static bool get_tpm_established_flag(void)
 {
-    return false;
+    TPM_BOOL tpmEstablished = false;
+
+    if (tpm_initialized) {
+        TPM_IO_TpmEstablished_Get(&tpmEstablished);
+    }
+
+    return (bool)tpmEstablished;
 }
 
 
@@ -298,10 +641,16 @@ static bool get_startup_error(void)
 
 /**
  * This function is called by tpm_tis.c once the TPM has processed
- * the last command and returned the response to the TIS.
+ * the last command and returned the response to the TIS. Since we
+ * store the volatile state into the block storage device we leave
+ * the provided buffer untouched.
  */
 static int save_volatile_data(void)
 {
+    TPM_RESULT res;
+    unsigned char *buffer;
+    uint32_t buflen;
+
     if (!tpm_initialized) {
         /* TPM was never initialized
            volatile_state.buffer may be NULL if TPM was never used.
@@ -309,20 +658,50 @@ static int save_volatile_data(void)
         return 0;
     }
 
+    /* have the serialized state written to a buffer only */
+#ifdef DEBUG_TPM_SR
+    fprintf(stderr,"tpm: Calling TPMLIB_VolatileAll_Store()\n");
+#endif
+    res = TPMLIB_VolatileAll_Store(&buffer, &buflen);
+
+    if (res != TPM_SUCCESS) {
+#ifdef DEBUG_TPM_SR
+        fprintf(stderr,"tpm: Error: Could not store TPM volatile state\n");
+#endif
+        return 1;
+    }
+
+#ifdef DEBUG_TPM_SR
+    fprintf(stderr,"tpm: got %d bytes of volatilestate [sum=%08x]\n",
+            buflen, memsum(buffer, buflen));
+#endif
+
+    set_sized_buffer(&volatile_state, buffer, buflen);
+    if (write_state_to_bs(VOLASTATE_TYPE)) {
+        return 1;
+    }
+    volatile_state.size = 0;
+    volatile_state.buffer = NULL;
+
+    /* make sure that everything has been written to disk */
+    fulfill_sync_to_bs_request(NULL);
+
     return 0;
 }
 
 
 static size_t realloc_buffer(TPMSizedBuffer *sb)
 {
-    size_t wanted_size = 4096;
+    TPM_RESULT res;
+    size_t wanted_size = tpmlib_get_prop(TPMPROP_TPM_BUFFER_MAX);
 
     if (sb->size != wanted_size) {
-        sb->buffer = qemu_realloc(&sb->buffer, wanted_size);
-        if (sb->buffer != NULL)
+        res = TPM_Realloc(&sb->buffer, wanted_size);
+        if (res == TPM_SUCCESS) {
             sb->size = wanted_size;
-        else
+        } else {
             sb->size = 0;
+        }
     }
     return sb->size;
 }
@@ -334,7 +713,8 @@ static const char *create_desc(void)
 
     if (!done) {
         snprintf(dev_description, sizeof(dev_description),
-                 "Skeleton TPM backend");
+                 "Qemu's built-in TPM; requires %ukb of block storage",
+                 MINIMUM_BS_SIZE_KB);
         done = 1;
     }
 
@@ -342,13 +722,15 @@ static const char *create_desc(void)
 }
 
 
+#define TPM_OPTS "id=vtpm-nvram"
+
 static bool handle_options(QemuOpts *opts)
 {
     const char *value;
 
     value = qemu_opt_get(opts, "path");
     if (value) {
-        // !!! handle path parameter
+        drive_add(IF_NONE, -1, value, TPM_OPTS);
     } else {
         fprintf(stderr,"-tpm is missing path= parameter\n");
         return false;
@@ -357,8 +739,8 @@ static bool handle_options(QemuOpts *opt
 }
 
 
-BackendTPMDriver skeleton = {
-    .id                             = "skeleton",
+BackendTPMDriver builtin = {
+    .id                             = "builtin",
     .desc                           = create_desc,
     .handle_options                 = handle_options,
     .init                           = init,
