Index: qemu-git/qemu-options.hx
===================================================================
--- qemu-git.orig/qemu-options.hx
+++ qemu-git/qemu-options.hx
@@ -1756,6 +1756,86 @@ ETEXI
 
 DEFHEADING()
 
+DEFHEADING(TPM device options:)
+
+#ifndef _WIN32
+# ifdef CONFIG_TPM
+DEF("tpm", HAS_ARG, QEMU_OPTION_tpm, \
+    "" \
+    "-tpm builtin,path=<path>[,model=<model>]\n" \
+    "                enable a builtin TPM with state in file in path\n" \
+    "-tpm model=?    to list available TPM device models\n" \
+    "-tpm ?          to list available TPM backend types\n",
+    QEMU_ARCH_I386)
+DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
+    "-tpmdev [builtin],id=str[,option][,option][,...]\n",
+    QEMU_ARCH_I386)
+# endif
+#endif
+STEXI
+
+The general form of a TPM device option is:
+@table @option
+
+@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
+@findex -tpmdev
+Backend type must be:
+@option{builtin}.
+
+The specific backend type will determine the applicable options.
+The @code{-tpmdev} options requires a @code{-device} option.
+
+Options to each backend are described below.
+
+Use ? to print all available TPM backend types.
+@example
+qemu -tpmdev ?
+@end example
+
+@item -tpmdev builtin ,id=@var{id}, path=@var{path}
+
+Creates an instance of the built-in TPM.
+
+@option{path} specifies the path to the QCoW2 image that will store
+the TPM's persistent data. @option{path} is required.
+
+To create a built-in TPM use the following two options:
+@example
+-tpmdev builtin,id=tpm0,path=<path_to_qcow2> -device tpm-tis,tpmdev=tpm0
+@end example
+Not that the @code{-tpmdev} id is @code{tpm0} and is referenced by
+@code{tpmdev=tpm0} in the device option.
+
+@end table
+
+The short form of a TPM device option is:
+@table @option
+
+@item -tpm @var{backend-type}, path=@var{path} [,model=@var{model}]
+@findex -tpm
+
+@option{model} specifies the device model. The default device model is a
+@code{tpm-tis} device model. @code{model} is optional.
+
+Use ? to print all available TPM models.
+@example
+qemu -tpm model=?
+@end example
+
+The other options have the same meaning as explained above.
+
+To create a built-in TPM use the following option:
+@example
+-tpm builtin, path=<path_to_qcow2>
+@end example
+
+@end table
+
+ETEXI
+
+
+DEFHEADING()
+
 DEFHEADING(Linux/Multiboot boot specific:)
 STEXI
 
Index: qemu-git/vl.c
===================================================================
--- qemu-git.orig/vl.c
+++ qemu-git/vl.c
@@ -137,6 +137,7 @@ int main(int argc, char **argv)
 #include "block.h"
 #include "blockdev.h"
 #include "block-migration.h"
+#include "tpm.h"
 #include "dma.h"
 #include "audio/audio.h"
 #include "migration.h"
@@ -2461,6 +2462,14 @@ int main(int argc, char **argv, char **e
                 ram_size = value;
                 break;
             }
+#ifdef CONFIG_TPM
+            case QEMU_OPTION_tpm:
+                tpm_config_parse(qemu_find_opts("tpm"), optarg);
+                break;
+            case QEMU_OPTION_tpmdev:
+                tpm_config_parse(qemu_find_opts("tpmdev"), optarg);
+                break;
+#endif
             case QEMU_OPTION_mempath:
                 mem_path = optarg;
                 break;
@@ -3107,6 +3116,12 @@ int main(int argc, char **argv, char **e
         exit(1);
     }
 
+#ifdef CONFIG_TPM
+    if (tpm_init() < 0) {
+        exit(1);
+    }
+#endif
+
     /* init the bluetooth world */
     if (foreach_device_config(DEV_BT, bt_parse))
         exit(1);
@@ -3357,6 +3372,9 @@ int main(int argc, char **argv, char **e
     quit_timers();
     net_cleanup();
     res_free();
+#ifdef CONFIG_TPM
+    tpm_cleanup();
+#endif
 
     return 0;
 }
Index: qemu-git/qemu-config.c
===================================================================
--- qemu-git.orig/qemu-config.c
+++ qemu-git/qemu-config.c
@@ -506,6 +506,50 @@ QemuOptsList qemu_boot_opts = {
     },
 };
 
+static QemuOptsList qemu_tpmdev_opts = {
+    .name = "tpmdev",
+    .implied_opt_name = "type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_tpmdev_opts.head),
+    .desc = {
+        {
+            .name = "type",
+            .type = QEMU_OPT_STRING,
+            .help = "Type of TPM backend",
+        },
+        {
+            .name = "path",
+            .type = QEMU_OPT_STRING,
+            .help = "Persistent storage for TPM state",
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_tpm_opts = {
+    .name = "tpm",
+    .implied_opt_name = "type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_tpm_opts.head),
+    .desc = {
+        {
+            .name = "type",
+            .type = QEMU_OPT_STRING,
+            .help = "Type of TPM backend",
+        },
+        {
+            .name = "model",
+            .type = QEMU_OPT_STRING,
+            .help = "Model of TPM frontend",
+        },
+        {
+            .name = "path",
+            .type = QEMU_OPT_STRING,
+            .help = "Persistent storage for TPM state",
+        },
+        { /* end of list */ }
+    },
+};
+
+
 static QemuOptsList *vm_config_groups[32] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
@@ -522,6 +566,8 @@ static QemuOptsList *vm_config_groups[32
     &qemu_option_rom_opts,
     &qemu_machine_opts,
     &qemu_boot_opts,
+    &qemu_tpmdev_opts,
+    &qemu_tpm_opts,
     NULL,
 };
 
Index: qemu-git/hw/tpm_tis.h
===================================================================
--- /dev/null
+++ qemu-git/hw/tpm_tis.h
@@ -0,0 +1,75 @@
+/*
+ * tpm_tis.h - include file for tpm_tis.c
+ *
+ * Copyright (C) 2006,2010,2011 IBM Corporation
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ *         David Safford <safford@us.ibm.com>
+ *
+ * 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.
+ */
+#ifndef _HW_TPM_TIS_H
+#define _HW_TPM_TIS_H
+
+#include "isa.h"
+#include "block_int.h"
+#include "qemu-thread.h"
+
+#include <stdint.h>
+
+#define TIS_ADDR_BASE       0xFED40000
+
+#define NUM_LOCALITIES      5     /* per spec */
+#define NO_LOCALITY         0xff
+
+#define IS_VALID_LOCTY(x)   ((x) < NUM_LOCALITIES)
+
+
+#define TPM_TIS_IRQ         5
+
+#define TIS_TPM_BUFFER_MAX  4096
+
+
+typedef struct TPMSizedBuffer {
+    uint32_t size;
+    uint8_t  *buffer;
+} TPMSizedBuffer;
+
+
+enum tis_state {
+    STATE_IDLE = 0,
+    STATE_READY,
+    STATE_COMPLETION,
+    STATE_EXECUTION,
+    STATE_RECEPTION,
+};
+
+
+void tis_reset_for_snapshot_resume(TPMState *s);
+
+
+/* utility functions */
+
+static inline uint16_t tis_get_size_from_buffer(const TPMSizedBuffer *sb)
+{
+    return (sb->buffer[4] << 8) + sb->buffer[5];
+}
+
+static inline void dumpBuffer(FILE *stream,
+                              unsigned char *buffer, unsigned int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+        if (i && !(i % 16)) {
+            fprintf(stream, "\n");
+        }
+        fprintf(stream, "%.2X ", buffer[i]);
+    }
+    fprintf(stream, "\n");
+}
+
+#endif /* _HW_TPM_TIS_H */
Index: qemu-git/tpm.c
===================================================================
--- /dev/null
+++ qemu-git/tpm.c
@@ -0,0 +1,279 @@
+/*
+ * TPM configuraion
+ *
+ * Copyright (C) 2011 IBM Corporation
+ * Copyright (C) 2011 Stefan Berger
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Based on net.c
+ */
+#include "config.h"
+
+#include "tpm.h"
+#include "monitor.h"
+#include "qerror.h"
+
+
+#ifdef CONFIG_TPM
+
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+
+static const TPMDriverOps *bes[] = {
+    NULL,
+};
+
+
+static const char *tpm_models[] = {
+    TPM_DEFAULT_DEVICE_MODEL,
+    NULL,
+};
+
+
+static QLIST_HEAD(, TPMBackend) tpm_backends =
+    QLIST_HEAD_INITIALIZER(tpm_backends);
+
+
+const TPMDriverOps *tpm_get_backend_driver(const char *id)
+{
+    int i;
+
+    for (i = 0; bes[i] != NULL; i++) {
+        if (!strcmp(bes[i]->id, id)) {
+            break;
+        }
+    }
+
+    return bes[i];
+}
+
+
+static void tpm_display_models(FILE *out)
+{
+    int i;
+
+    fprintf(stderr, "qemu: Supported TPM models: ");
+    for (i = 0 ; tpm_models[i]; i++) {
+        fprintf(stderr, "%s%c", tpm_models[i], tpm_models[i+1] ? ',' : '\n');
+    }
+}
+
+
+static int tpm_check_model(const char *model)
+{
+    int i;
+
+    for (i = 0 ; tpm_models[i]; i++) {
+        if (strcmp(tpm_models[i], model) == 0) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+
+void tpm_display_backend_drivers(FILE *out)
+{
+    int i;
+
+    fprintf(out, "Supported TPM types (choose only one):\n");
+
+    for (i = 0; bes[i] != NULL; i++) {
+        fprintf(out, "%7s   %s",
+                bes[i]->id, bes[i]->desc());
+        fprintf(out, "\n");
+    }
+    fprintf(out, "\n");
+}
+
+
+TPMBackend *qemu_find_tpm(const char *id)
+{
+    TPMBackend *drv;
+
+    QLIST_FOREACH(drv, &tpm_backends, list) {
+        if (!strcmp(drv->id, id)) {
+            return drv;
+        }
+    }
+
+    return NULL;
+}
+
+
+void do_info_tpm(Monitor *mon)
+{
+    TPMBackend *drv;
+    const char *model;
+
+    monitor_printf(mon, "TPM devices:\n");
+
+    QLIST_FOREACH(drv, &tpm_backends, list) {
+        model = drv->model ? drv->model : TPM_DEFAULT_DEVICE_MODEL;
+        monitor_printf(mon, "  %s: model=%s,id=%s\n",
+                       drv->ops->id, model, drv->id);
+    }
+}
+
+/*
+ * Create those TPMs that were created with -tpm rather than -tpmdev.
+ * The ones created with -tpm have a 'model' name.
+ */
+void qemu_create_tpm(void)
+{
+    TPMBackend *drv;
+
+    QLIST_FOREACH(drv, &tpm_backends, list) {
+        if (drv->model) {
+            if (strcmp(drv->model, TPM_DEFAULT_DEVICE_MODEL) == 0) {
+                isa_create_simple(drv->model);
+            }
+        }
+    }
+}
+
+
+static int configure_tpm(QemuOpts *opts, int is_tpmdev)
+{
+    const char *value;
+    const char *id = TPM_DEFAULT_DEVICE_ID;
+    const char *model =  NULL;
+    const TPMDriverOps *be;
+    TPMBackend *drv;
+
+    if (!QLIST_EMPTY(&tpm_backends)) {
+        fprintf(stderr, "Only one TPM is allowed.\n");
+        return 1;
+    }
+
+    if (is_tpmdev) {
+        id = qemu_opts_id(opts);
+        if (id == NULL) {
+            qerror_report(QERR_MISSING_PARAMETER, "id");
+            return 1;
+        }
+    } else {
+        model = qemu_opt_get(opts, "model");
+        if (model) {
+            if (strcmp(model, "?") == 0) {
+                tpm_display_models(stdout);
+                return 1;
+            }
+            if (!tpm_check_model(model)) {
+                qerror_report(QERR_INVALID_PARAMETER_VALUE, "model",
+                              "a tpm model");
+                tpm_display_models(stderr);
+                return 1;
+            }
+        } else {
+            model = TPM_DEFAULT_DEVICE_MODEL;
+        }
+    }
+
+    value = qemu_opt_get(opts, "type");
+    if (!value) {
+        qerror_report(QERR_MISSING_PARAMETER, "type");
+        tpm_display_backend_drivers(stderr);
+        return 1;
+    }
+
+    be = tpm_get_backend_driver(value);
+    if (be == NULL) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+                      "a tpm backend type");
+        tpm_display_backend_drivers(stderr);
+        return 1;
+    }
+
+    assert((is_tpmdev && model == NULL) || (!is_tpmdev && model != NULL));
+
+    drv = be->create(opts, id, model);
+    if (!drv) {
+        return 1;
+    }
+
+    QLIST_INSERT_HEAD(&tpm_backends, drv, list);
+
+    return 0;
+}
+
+
+static int tpm_init_tpmdev(QemuOpts *opts, void *dummy)
+{
+    return configure_tpm(opts, 1);
+}
+
+
+static int tpm_init_tpm(QemuOpts *opts, void *dummy)
+{
+    return configure_tpm(opts, 0);
+}
+
+
+int tpm_init(void)
+{
+    if (qemu_opts_foreach(qemu_find_opts("tpmdev"),
+                          tpm_init_tpmdev, NULL, 1) != 0) {
+        return -1;
+    }
+
+    if (qemu_opts_foreach(qemu_find_opts("tpm"),
+                          tpm_init_tpm, NULL, 1) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+
+void tpm_cleanup(void)
+{
+    TPMBackend *drv, *next;
+
+    QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) {
+        QLIST_REMOVE(drv, list);
+        drv->ops->destroy(drv);
+    }
+}
+
+
+void tpm_config_parse(QemuOptsList *opts_list, const char *optarg)
+{
+    QemuOpts *opts;
+
+    if (strcmp("none", optarg) != 0) {
+        if (*optarg == '?') {
+            tpm_display_backend_drivers(stdout);
+            exit(0);
+        }
+        opts = qemu_opts_parse(opts_list, optarg, 1);
+        if (!opts) {
+            exit(1);
+        }
+    }
+}
+
+# else /* TARGET_I386 || TARGET_X86_64 */
+
+void tpm_config_parse(QemuOptsList *opts_list, const char *optarg)
+{
+}
+
+int tpm_init(void)
+{
+    return 0;
+}
+
+void tpm_cleanup(void)
+{
+}
+
+void do_info_tpm(Monitor *mon)
+{
+    monitor_printf(mon, "TPM support: not compiled\n");
+}
+
+# endif
+#endif /* CONFIG_TPM */
Index: qemu-git/tpm.h
===================================================================
--- /dev/null
+++ qemu-git/tpm.h
@@ -0,0 +1,112 @@
+#ifndef _HW_TPM_CONFIG_H
+#define _HW_TPM_CONFIG_H
+
+struct TPMState;
+typedef struct TPMState TPMState;
+
+#include "hw/tpm_tis.h"
+
+struct TPMDriverOps;
+typedef struct TPMDriverOps TPMDriverOps;
+
+typedef struct TPMBackend {
+    char *id;
+    char *model;
+    TPMDriverOps *ops;
+
+    QLIST_ENTRY(TPMBackend) list;
+} TPMBackend;
+
+
+/* locality data  -- all fields are persisted */
+typedef struct TPMLocality {
+    enum tis_state state;
+    uint8_t access;
+    uint8_t sts;
+    uint32_t inte;
+    uint32_t ints;
+
+    uint16_t w_offset;
+    uint16_t r_offset;
+    TPMSizedBuffer w_buffer;
+    TPMSizedBuffer r_buffer;
+} TPMLocality;
+
+
+/* overall state of the TPM interface */
+struct TPMState {
+    ISADevice busdev;
+
+    uint32_t offset;
+    uint8_t buf[TIS_TPM_BUFFER_MAX];
+
+    uint8_t active_locty;
+    uint8_t aborting_locty;
+    uint8_t next_locty;
+
+    uint8_t command_locty;
+    TPMLocality loc[NUM_LOCALITIES];
+
+    qemu_irq irq;
+    uint32_t irq_num;
+
+    QemuMutex state_lock;
+    QemuCond  from_tpm_cond;
+    QemuCond  to_tpm_cond;
+    bool      to_tpm_execute;
+
+    bool      tpm_initialized;
+
+    char *backend;
+    TPMBackend *be_driver;
+};
+
+
+typedef void (TPMRecvDataCB)(TPMState *s, uint8_t locty);
+
+struct TPMDriverOps {
+    const char *id;
+    /* get a descriptive text of the backend to display to the user */
+    const char *(*desc)(void);
+
+    void (*job_for_main_thread)(void *);
+
+    TPMBackend *(*create)(QemuOpts *, const char *id, const char *model);
+    void (*destroy)(TPMBackend *drv);
+
+    /* initialize the backend */
+    int (*init)(TPMState *s, TPMRecvDataCB *datacb);
+    /* start up the TPM on the backend early if possible */
+    int (*early_startup_tpm)(void);
+    /* start up the TPM on the backend late if necessary */
+    int (*late_startup_tpm)(void);
+    /* returns true if nothing will ever answer TPM requests */
+    bool (*had_startup_error)(void);
+
+    size_t (*realloc_buffer)(TPMSizedBuffer *sb);
+
+    void (*reset)(void);
+
+    /* called to trigger the saving of the volatile data;
+       called before the VM suspends / migrates */
+    int (*save_volatile_data)(void);
+    /* triggers the loading of the volatile data */
+    int (*load_volatile_data)(TPMState *s);
+
+    bool (*get_tpm_established_flag)(void);
+};
+
+#define TPM_DEFAULT_DEVICE_ID    "tpm0"
+#define TPM_DEFAULT_DEVICE_MODEL "tpm-tis"
+
+void tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
+int tpm_init(void);
+void tpm_cleanup(void);
+void qemu_create_tpm(void);
+TPMBackend *qemu_find_tpm(const char *id);
+void do_info_tpm(Monitor *mon);
+void tpm_display_backend_drivers(FILE *out);
+const TPMDriverOps *tpm_get_backend_driver(const char *id);
+
+
+#endif /* _HW_TPM_CONFIG_H */
Index: qemu-git/hw/pc.c
===================================================================
--- qemu-git.orig/hw/pc.c
+++ qemu-git/hw/pc.c
@@ -42,6 +42,7 @@
 #include "blockdev.h"
 #include "ui/qemu-spice.h"
 #include "memory.h"
+#include "tpm.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -61,7 +62,7 @@
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
 
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
-#define ACPI_DATA_SIZE       0x10000
+#define ACPI_DATA_SIZE       0x20000
 #define BIOS_CFG_IOPORT 0x510
 #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
 #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
@@ -1179,6 +1180,10 @@ void pc_basic_device_init(qemu_irq *isa_
         fd[i] = drive_get(IF_FLOPPY, 0, i);
     }
     fdctrl_init_isa(fd);
+
+#ifdef CONFIG_TPM
+    qemu_create_tpm();
+#endif
 }
 
 void pc_pci_device_init(PCIBus *pci_bus)
Index: qemu-git/monitor.c
===================================================================
--- qemu-git.orig/monitor.c
+++ qemu-git/monitor.c
@@ -47,6 +47,7 @@
 #include "migration.h"
 #include "kvm.h"
 #include "acl.h"
+#include "tpm.h"
 #include "qint.h"
 #include "qfloat.h"
 #include "qlist.h"
@@ -3139,6 +3140,15 @@ static const mon_cmd_t info_cmds[] = {
         .mhandler.info = do_info_trace_events,
     },
 #endif
+#if defined(CONFIG_TPM)
+    {
+        .name       = "tpm",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the TPM devices",
+        .mhandler.info = do_info_tpm,
+    },
+#endif
     {
         .name       = NULL,
     },
Index: qemu-git/hmp-commands.hx
===================================================================
--- qemu-git.orig/hmp-commands.hx
+++ qemu-git/hmp-commands.hx
@@ -1351,6 +1351,8 @@ show device tree
 show qdev device model list
 @item info roms
 show roms
+@item info tpm
+show the TPM devices
 @end table
 ETEXI
 
Index: qemu-git/Makefile.target
===================================================================
--- qemu-git.orig/Makefile.target
+++ qemu-git/Makefile.target
@@ -200,6 +200,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-y += memory.o
 LIBS+=-lz
+obj-y += tpm.o
 
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
