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

[qemu-xen staging] Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2020-06-24' into staging



=== This changeset includes merge from high-traffic branch ===
Commits on that branch are not reported individually.

commit 4abf70a661a5df3886ac9d7c19c3617fa92b922a
Merge: 6651620b92bc08cde07cb500e9a43dba7bd9b2b7 
24b861c0386a17ea31eb824310c21118fb7be883
Author:     Peter Maydell <peter.maydell@xxxxxxxxxx>
AuthorDate: Fri Jul 3 15:34:44 2020 +0100
Commit:     Peter Maydell <peter.maydell@xxxxxxxxxx>
CommitDate: Fri Jul 3 15:34:45 2020 +0100

    Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2020-06-24' 
into staging
    
    Block patches:
    - Two iotest fixes
    
    # gpg: Signature made Wed 24 Jun 2020 09:00:51 BST
    # gpg:                using RSA key 91BEB60A30DB3E8857D11829F407DB0061D5CF40
    # gpg:                issuer "mreitz@xxxxxxxxxx"
    # gpg: Good signature from "Max Reitz <mreitz@xxxxxxxxxx>" [full]
    # Primary key fingerprint: 91BE B60A 30DB 3E88 57D1  1829 F407 DB00 61D5 
CF40
    
    * remotes/maxreitz/tags/pull-block-2020-06-24:
      iotests: don't test qcow2.py inside 291
      iotests: Fix 051 output after qdev_init_nofail() removal
    
    Signed-off-by: Peter Maydell <peter.maydell@xxxxxxxxxx>
 MAINTAINERS                                      |   16 +-
 Makefile                                         |   12 +-
 Makefile.objs                                    |    1 +
 accel/kvm/kvm-all.c                              |   21 +-
 accel/tcg/translate-all.c                        |    6 +-
 backends/Kconfig                                 |    1 +
 backends/Makefile.objs                           |    2 +-
 backends/tpm.c                                   |  208 ----
 backends/tpm/Kconfig                             |   14 +
 backends/tpm/Makefile.objs                       |    4 +
 backends/tpm/tpm_backend.c                       |  208 ++++
 backends/tpm/tpm_emulator.c                      |  997 +++++++++++++++
 backends/tpm/tpm_int.h                           |   88 ++
 backends/tpm/tpm_ioctl.h                         |  271 +++++
 backends/tpm/tpm_passthrough.c                   |  405 ++++++
 backends/tpm/tpm_util.c                          |  380 ++++++
 backends/tpm/trace-events                        |   33 +
 block/nvme.c                                     |  218 +++-
 block/trace-events                               |    2 +-
 blockdev.c                                       |   27 +-
 chardev/char-socket.c                            |    9 +-
 configure                                        |  108 +-
 cpus.c                                           |   15 +-
 docs/index.html.in                               |    4 +-
 docs/nvdimm.txt                                  |   10 +
 docs/qdev-device-use.txt                         |   17 +-
 docs/specs/tpm.rst                               |   16 +-
 docs/system/deprecated.rst                       |   71 +-
 exec.c                                           |   54 +-
 fpu/softfloat.c                                  |   87 +-
 hw/9pfs/9p.c                                     |    6 +-
 hw/acpi/aml-build.c                              |   51 +-
 hw/acpi/generic_event_device.c                   |   29 +
 hw/acpi/pcihp.c                                  |    3 +-
 hw/acpi/piix4.c                                  |   23 +-
 hw/arm/Kconfig                                   |    8 +-
 hw/arm/armsse.c                                  |   61 +-
 hw/arm/armv7m.c                                  |    7 +-
 hw/arm/aspeed.c                                  |   62 +-
 hw/arm/aspeed_ast2600.c                          |   35 +-
 hw/arm/aspeed_soc.c                              |   29 +-
 hw/arm/bcm2835_peripherals.c                     |   12 +-
 hw/arm/cubieboard.c                              |    2 +-
 hw/arm/exynos4210.c                              |    2 +-
 hw/arm/fsl-imx25.c                               |   12 +-
 hw/arm/fsl-imx6.c                                |   12 +-
 hw/arm/imx25_pdk.c                               |    2 +-
 hw/arm/mcimx6ul-evk.c                            |    2 +-
 hw/arm/mcimx7d-sabre.c                           |    2 +-
 hw/arm/mps2-tz.c                                 |   23 +-
 hw/arm/mps2.c                                    |   67 +-
 hw/arm/msf2-som.c                                |    4 +-
 hw/arm/nrf51_soc.c                               |    6 +-
 hw/arm/nseries.c                                 |    4 +-
 hw/arm/orangepi.c                                |    2 +-
 hw/arm/raspi.c                                   |    2 +-
 hw/arm/realview.c                                |    3 +-
 hw/arm/sabrelite.c                               |    6 +-
 hw/arm/stm32f205_soc.c                           |    2 +-
 hw/arm/stm32f405_soc.c                           |    2 +-
 hw/arm/versatilepb.c                             |    3 +-
 hw/arm/vexpress.c                                |    6 +-
 hw/arm/virt-acpi-build.c                         |   34 +
 hw/arm/virt.c                                    |  124 +-
 hw/arm/xilinx_zynq.c                             |    7 +-
 hw/arm/xlnx-versal-virt.c                        |    2 +-
 hw/arm/xlnx-zcu102.c                             |   10 +-
 hw/block/fdc.c                                   |  193 ++-
 hw/block/nand.c                                  |    2 +-
 hw/block/pflash_cfi01.c                          |    6 +-
 hw/block/pflash_cfi02.c                          |    2 +-
 hw/char/ibex_uart.c                              |    2 +-
 hw/char/virtio-serial-bus.c                      |    4 +-
 hw/core/bus.c                                    |    8 +-
 hw/core/machine.c                                |    8 +-
 hw/core/numa.c                                   |    7 +
 hw/core/qdev-properties-system.c                 |  151 ++-
 hw/core/qdev-properties.c                        |   17 +
 hw/display/ati.c                                 |   92 +-
 hw/display/ati_dbg.c                             |    1 +
 hw/display/ati_regs.h                            |    1 +
 hw/display/sm501.c                               |  157 ++-
 hw/display/trace-events                          |   12 +
 hw/display/virtio-gpu-pci.c                      |    2 +-
 hw/display/virtio-vga.c                          |    2 +-
 hw/dma/sparc32_dma.c                             |    6 +-
 hw/dma/xilinx_axidma.c                           |   12 +-
 hw/hyperv/vmbus.c                                |    3 +-
 hw/i2c/core.c                                    |   18 +-
 hw/i2c/versatile_i2c.c                           |   38 +-
 hw/i386/acpi-build.c                             |  214 +---
 hw/i386/amd_iommu.c                              |    6 +-
 hw/i386/fw_cfg.c                                 |   28 +
 hw/i386/fw_cfg.h                                 |    1 +
 hw/i386/pc.c                                     |   34 +-
 hw/i386/pc_piix.c                                |    1 +
 hw/i386/pc_q35.c                                 |    1 +
 hw/i386/x86.c                                    |    8 +-
 hw/ide/qdev.c                                    |    4 +-
 hw/input/adb-kbd.c                               |   42 +-
 hw/input/adb-mouse.c                             |   65 +-
 hw/input/adb.c                                   |  210 +++-
 hw/input/pckbd.c                                 |   31 +
 hw/input/trace-events                            |   27 +-
 hw/intc/Kconfig                                  |    3 +
 hw/intc/Makefile.objs                            |    1 +
 hw/intc/loongson_liointc.c                       |  242 ++++
 hw/isa/isa-superio.c                             |   18 +-
 hw/m68k/q800.c                                   |    3 +-
 hw/microblaze/petalogix_ml605_mmu.c              |    5 +-
 hw/mips/cps.c                                    |   35 +-
 hw/misc/mac_via.c                                |  411 ++++---
 hw/misc/macio/cuda.c                             |   60 +-
 hw/misc/macio/macio.c                            |    3 +-
 hw/misc/macio/pmu.c                              |   47 +-
 hw/misc/pca9552.c                                |  217 +++-
 hw/misc/trace-events                             |    7 +
 hw/net/virtio-net.c                              |    2 +-
 hw/net/xilinx_axienet.c                          |   12 +-
 hw/pci/pci.c                                     |    3 -
 hw/pci/pcie.c                                    |    2 +-
 hw/pci/shpc.c                                    |    2 +-
 hw/ppc/mac_newworld.c                            |    2 -
 hw/ppc/pnv.c                                     |   12 +-
 hw/ppc/spapr.c                                   |   10 +-
 hw/ppc/spapr_caps.c                              |   28 +-
 hw/ppc/spapr_drc.c                               |    4 +-
 hw/ppc/spapr_pci.c                               |    4 +-
 hw/ppc/spapr_vio.c                               |    6 +-
 hw/riscv/riscv_hart.c                            |   14 +-
 hw/riscv/sifive_u.c                              |   12 +-
 hw/s390x/ap-bridge.c                             |    2 +-
 hw/s390x/css-bridge.c                            |    2 +-
 hw/s390x/s390-pci-bus.c                          |   14 +-
 hw/scsi/megasas.c                                |   36 +-
 hw/scsi/scsi-bus.c                               |    4 +-
 hw/scsi/virtio-scsi.c                            |    4 +-
 hw/scsi/vmw_pvscsi.c                             |    2 +-
 hw/sd/milkymist-memcard.c                        |    7 +-
 hw/sd/pxa2xx_mmci.c                              |   15 +-
 hw/sd/sd.c                                       |    2 +-
 hw/sd/ssi-sd.c                                   |    3 +-
 hw/sparc64/sun4u.c                               |    9 +-
 hw/tpm/Kconfig                                   |   21 +-
 hw/tpm/Makefile.objs                             |    3 -
 hw/tpm/tpm_crb.c                                 |    4 +-
 hw/tpm/tpm_emulator.c                            |  997 ---------------
 hw/tpm/tpm_int.h                                 |   75 --
 hw/tpm/tpm_ioctl.h                               |  271 -----
 hw/tpm/tpm_passthrough.c                         |  405 ------
 hw/tpm/tpm_ppi.c                                 |    1 +
 hw/tpm/tpm_ppi.h                                 |    1 -
 hw/tpm/tpm_prop.h                                |   31 +
 hw/tpm/tpm_spapr.c                               |    4 +-
 hw/tpm/tpm_tis.h                                 |    1 -
 hw/tpm/tpm_tis_common.c                          |   11 +-
 hw/tpm/tpm_tis_isa.c                             |    3 +-
 hw/tpm/tpm_tis_sysbus.c                          |    3 +-
 hw/tpm/tpm_util.c                                |  377 ------
 hw/tpm/tpm_util.h                                |   85 --
 hw/tpm/trace-events                              |   34 +-
 hw/usb/bus.c                                     |    2 +-
 hw/usb/dev-mtp.c                                 |    2 -
 hw/usb/dev-smartcard-reader.c                    |    2 +-
 hw/usb/hcd-xhci.h                                |    2 +-
 hw/virtio/vhost-user.c                           |   12 +-
 hw/virtio/virtio-iommu-pci.c                     |    4 +-
 hw/watchdog/cmsdk-apb-watchdog.c                 |    1 +
 hw/watchdog/trace-events                         |    1 +
 hw/xen/Makefile.objs                             |    2 +-
 hw/xen/xen-bus.c                                 |    2 +-
 hw/xen/xen-legacy-backend.c                      |    2 +-
 hw/xtensa/xtfpga.c                               |    3 +-
 include/block/block.h                            |    4 +-
 include/exec/cpu-all.h                           |    8 +-
 include/exec/cpu-defs.h                          |    7 +-
 include/fpu/softfloat.h                          |    3 +
 include/hw/acpi/acpi-defs.h                      |   18 -
 include/hw/arm/aspeed.h                          |   12 +-
 include/hw/block/fdc.h                           |    5 +-
 include/hw/hyperv/vmbus-bridge.h                 |    3 +-
 include/hw/i2c/arm_sbcon_i2c.h                   |   35 +
 include/hw/i2c/i2c.h                             |    2 +
 include/hw/i386/pc.h                             |    1 -
 include/hw/input/adb.h                           |   26 +-
 include/hw/misc/mac_via.h                        |    2 +-
 include/hw/misc/macio/cuda.h                     |    4 -
 include/hw/misc/macio/pmu.h                      |    4 -
 include/hw/misc/pca9552.h                        |   16 +-
 include/hw/ppc/xive_regs.h                       |    2 +-
 include/hw/qdev-core.h                           |    5 +-
 include/hw/qdev-properties.h                     |   18 +-
 include/qemu/coroutine_int.h                     |    5 +
 include/qemu/osdep.h                             |   57 +-
 include/sysemu/blockdev.h                        |    2 +
 include/sysemu/tpm_util.h                        |   72 ++
 memory.c                                         |   29 +-
 migration/qemu-file.c                            |    2 +-
 migration/rdma.c                                 |   19 +-
 pc-bios/bios-256k.bin                            |  Bin 262144 -> 262144 bytes
 pc-bios/bios.bin                                 |  Bin 131072 -> 131072 bytes
 pc-bios/vgabios-ati.bin                          |  Bin 39424 -> 39424 bytes
 pc-bios/vgabios-bochs-display.bin                |  Bin 28672 -> 28672 bytes
 pc-bios/vgabios-cirrus.bin                       |  Bin 38912 -> 38912 bytes
 pc-bios/vgabios-qxl.bin                          |  Bin 39424 -> 39424 bytes
 pc-bios/vgabios-ramfb.bin                        |  Bin 28672 -> 28672 bytes
 pc-bios/vgabios-stdvga.bin                       |  Bin 39424 -> 39424 bytes
 pc-bios/vgabios-virtio.bin                       |  Bin 39424 -> 39424 bytes
 pc-bios/vgabios-vmware.bin                       |  Bin 39424 -> 39424 bytes
 pc-bios/vgabios.bin                              |  Bin 38912 -> 38912 bytes
 qemu-options.hx                                  |    9 +-
 qga/commands-posix.c                             |    1 +
 replay/replay.c                                  |    2 +-
 roms/config.seabios-128k                         |    3 +
 roms/seabios                                     |    2 +-
 scripts/minikconf.py                             |    6 +-
 scripts/performance/topN_callgrind.py            |  140 +++
 scripts/performance/topN_perf.py                 |  149 +++
 scripts/tracetool.py                             |    2 +-
 scripts/tracetool/__init__.py                    |    2 +-
 scripts/tracetool/backend/__init__.py            |    2 +-
 scripts/tracetool/backend/dtrace.py              |    2 +-
 scripts/tracetool/backend/log.py                 |    2 +-
 scripts/tracetool/backend/simple.py              |    2 +-
 scripts/tracetool/backend/ust.py                 |    2 +-
 scripts/tracetool/format/__init__.py             |    2 +-
 scripts/tracetool/format/c.py                    |    2 +-
 scripts/tracetool/format/d.py                    |    2 +-
 scripts/tracetool/format/h.py                    |    2 +-
 scripts/tracetool/format/stap.py                 |    2 +-
 scripts/tracetool/format/tcg_h.py                |    2 +-
 scripts/tracetool/format/tcg_helper_c.py         |    2 +-
 scripts/tracetool/format/tcg_helper_h.py         |    2 +-
 scripts/tracetool/format/tcg_helper_wrapper_h.py |    2 +-
 scripts/tracetool/transform.py                   |    2 +-
 scripts/tracetool/vcpu.py                        |    2 +-
 softmmu/vl.c                                     |    8 +
 stubs/Makefile.objs                              |    1 +
 stubs/cmos.c                                     |    7 +
 target/arm/Makefile.objs                         |    1 +
 target/arm/cpu.c                                 |   83 +-
 target/arm/cpu.h                                 |   52 +-
 target/arm/cpu64.c                               |   15 +-
 target/arm/helper-a64.c                          |   96 +-
 target/arm/helper-a64.h                          |   16 +
 target/arm/helper-sve.h                          |  488 ++++++++
 target/arm/helper.c                              |  421 +++++--
 target/arm/helper.h                              |    2 +
 target/arm/internals.h                           |  153 ++-
 target/arm/kvm.c                                 |    4 +-
 target/arm/kvm64.c                               |   14 +-
 target/arm/kvm_arm.h                             |   21 +-
 target/arm/m_helper.c                            |   11 +-
 target/arm/mte_helper.c                          |  906 ++++++++++++++
 target/arm/neon-dp.decode                        |  106 ++
 target/arm/op_helper.c                           |   16 +
 target/arm/sve_helper.c                          |  614 ++++++++--
 target/arm/tlb_helper.c                          |   13 +-
 target/arm/translate-a64.c                       |  677 +++++++++--
 target/arm/translate-a64.h                       |    5 +
 target/arm/translate-neon.inc.c                  | 1191 +++++++++++++++++-
 target/arm/translate-sve.c                       | 1420 ++++++++++++++--------
 target/arm/translate-vfp.inc.c                   |    9 +-
 target/arm/translate.c                           | 1080 +---------------
 target/arm/translate.h                           |   31 +-
 target/i386/cpu.c                                |    9 +
 target/i386/fpu_helper.c                         | 1396 +++++++++++++++++++--
 target/i386/kvm.c                                |   46 +-
 target/m68k/softfloat.c                          |   83 --
 target/m68k/softfloat.h                          |    1 -
 target/mips/kvm.c                                |   26 +
 target/mips/kvm_mips.h                           |   11 +
 target/ppc/translate_init.inc.c                  |    5 -
 target/xtensa/cpu.h                              |    1 +
 target/xtensa/overlay_tool.h                     |    8 +-
 target/xtensa/translate.c                        |   60 +-
 tests/check-block-qdict.c                        |   24 +-
 tests/check-block.sh                             |   12 +-
 tests/check-qobject.c                            |    5 +-
 tests/check-qom-proplist.c                       |   14 +-
 tests/data/acpi/pc/DSDT                          |  Bin 5014 -> 4934 bytes
 tests/data/acpi/pc/DSDT.acpihmat                 |  Bin 6338 -> 6258 bytes
 tests/data/acpi/pc/DSDT.bridge                   |  Bin 6873 -> 6793 bytes
 tests/data/acpi/pc/DSDT.cphp                     |  Bin 5477 -> 5397 bytes
 tests/data/acpi/pc/DSDT.dimmpxm                  |  Bin 6667 -> 6587 bytes
 tests/data/acpi/pc/DSDT.ipmikcs                  |  Bin 5086 -> 5006 bytes
 tests/data/acpi/pc/DSDT.memhp                    |  Bin 6373 -> 6293 bytes
 tests/data/acpi/pc/DSDT.numamem                  |  Bin 5020 -> 4940 bytes
 tests/data/acpi/q35/DSDT                         |  Bin 7752 -> 7678 bytes
 tests/data/acpi/q35/DSDT.acpihmat                |  Bin 9076 -> 9002 bytes
 tests/data/acpi/q35/DSDT.bridge                  |  Bin 7769 -> 7695 bytes
 tests/data/acpi/q35/DSDT.cphp                    |  Bin 8215 -> 8141 bytes
 tests/data/acpi/q35/DSDT.dimmpxm                 |  Bin 9405 -> 9331 bytes
 tests/data/acpi/q35/DSDT.ipmibt                  |  Bin 7827 -> 7753 bytes
 tests/data/acpi/q35/DSDT.memhp                   |  Bin 9111 -> 9037 bytes
 tests/data/acpi/q35/DSDT.mmio64                  |  Bin 8882 -> 8808 bytes
 tests/data/acpi/q35/DSDT.numamem                 |  Bin 7758 -> 7684 bytes
 tests/data/acpi/q35/DSDT.tis                     |  Bin 8357 -> 8283 bytes
 tests/qemu-iotests/172                           |   27 +-
 tests/qemu-iotests/172.out                       |  642 +++++++++-
 tests/qtest/arm-cpu-features.c                   |   38 +-
 tests/qtest/bios-tables-test-allowed-diff.h      |   18 +
 tests/qtest/bios-tables-test.c                   |    2 +-
 tests/qtest/libqos/pci-pc.c                      |    2 +-
 tests/qtest/test-x86-cpuid-compat.c              |    4 +-
 tests/qtest/tpm-emu.c                            |    2 +-
 tests/qtest/usb-hcd-ehci-test.c                  |    2 +-
 tests/tcg/i386/test-i386-f2xm1.c                 | 1140 +++++++++++++++++
 tests/tcg/i386/test-i386-fpatan.c                | 1071 ++++++++++++++++
 tests/tcg/i386/test-i386-fyl2x.c                 | 1161 ++++++++++++++++++
 tests/tcg/i386/test-i386-fyl2xp1.c               | 1156 ++++++++++++++++++
 tests/test-base64.c                              |    3 +-
 tests/test-bdrv-graph-mod.c                      |    4 +-
 tests/test-block-iothread.c                      |    3 +-
 tests/test-crypto-cipher.c                       |    8 +-
 tests/test-io-task.c                             |    4 +-
 tests/test-logging.c                             |   12 +-
 tests/test-qemu-opts.c                           |   22 +-
 tests/test-replication.c                         |  109 +-
 tests/test-string-input-visitor.c                |   33 +-
 tests/test-string-output-visitor.c               |   16 +-
 tests/test-util-filemonitor.c                    |    1 +
 trace/simple.c                                   |   20 +-
 trace/simple.h                                   |    2 +-
 ui/vnc.c                                         |    6 +-
 util/coroutine-sigaltstack.c                     |    4 +
 util/coroutine-ucontext.c                        |   28 +
 util/getauxval.c                                 |   10 +
 util/oslib-posix.c                               |   15 +
 util/qemu-timer.c                                |   32 +-
 330 files changed, 17977 insertions(+), 6506 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 51a45703b8..dec252f38b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -842,6 +842,7 @@ M: Peter Maydell <peter.maydell@xxxxxxxxxx>
 L: qemu-arm@xxxxxxxxxx
 S: Maintained
 F: hw/*/versatile*
+F: include/hw/i2c/arm_sbcon_i2c.h
 F: hw/misc/arm_sysctl.c
 F: docs/system/arm/versatile.rst
 
@@ -1095,6 +1096,12 @@ F: hw/isa/vt82c686.c
 F: hw/pci-host/bonito.c
 F: include/hw/isa/vt82c686.h
 
+Loongson-3 virtual platforms
+M: Huacai Chen <chenhc@xxxxxxxxxx>
+R: Jiaxun Yang <jiaxun.yang@xxxxxxxxxxx>
+S: Maintained
+F: hw/intc/loongson_liointc.c
+
 Boston
 M: Paul Burton <pburton@xxxxxxxxxxxx>
 R: Aleksandar Rikalo <aleksandar.rikalo@xxxxxxxxxx>
@@ -2430,7 +2437,7 @@ F: hw/tpm/*
 F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
-F: backends/tpm.c
+F: backends/tpm/
 F: tests/qtest/*tpm*
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
@@ -3018,3 +3025,10 @@ M: Peter Maydell <peter.maydell@xxxxxxxxxx>
 S: Maintained
 F: docs/conf.py
 F: docs/*/conf.py
+
+Miscellaneous
+-------------
+Performance Tools and Tests
+M: Ahmed Karaman <ahmedkhaledkaraman@xxxxxxxxx>
+S: Maintained
+F: scripts/performance/
diff --git a/Makefile b/Makefile
index 48f23aa978..b1b8a5a6d0 100644
--- a/Makefile
+++ b/Makefile
@@ -418,7 +418,7 @@ MINIKCONF_ARGS = \
     CONFIG_LINUX=$(CONFIG_LINUX) \
     CONFIG_PVRDMA=$(CONFIG_PVRDMA)
 
-MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig
+MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/backends/Kconfig 
$(SRC_PATH)/hw/Kconfig
 MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig)
 MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
 
@@ -873,8 +873,9 @@ install-sphinxdocs: sphinxdocs
 install-doc: $(DOCS) install-sphinxdocs
        $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
        $(INSTALL_DATA) $(MANUAL_BUILDDIR)/index.html "$(DESTDIR)$(qemu_docdir)"
-       $(INSTALL_DATA) docs/interop/qemu-qmp-ref.html 
"$(DESTDIR)$(qemu_docdir)"
-       $(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)"
+       $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop"
+       $(INSTALL_DATA) docs/interop/qemu-qmp-ref.html 
"$(DESTDIR)$(qemu_docdir)/interop"
+       $(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt 
"$(DESTDIR)$(qemu_docdir)/interop"
 ifdef CONFIG_POSIX
        $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
        $(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu.1 
"$(DESTDIR)$(mandir)/man1"
@@ -892,8 +893,9 @@ ifdef CONFIG_TRACE_SYSTEMTAP
 endif
 ifneq (,$(findstring qemu-ga,$(TOOLS)))
        $(INSTALL_DATA) $(MANUAL_BUILDDIR)/interop/qemu-ga.8 
"$(DESTDIR)$(mandir)/man8"
-       $(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
-       $(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)"
+       $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop"
+       $(INSTALL_DATA) docs/interop/qemu-ga-ref.html 
"$(DESTDIR)$(qemu_docdir)/interop"
+       $(INSTALL_DATA) docs/interop/qemu-ga-ref.txt 
"$(DESTDIR)$(qemu_docdir)/interop"
        $(INSTALL_DATA) docs/interop/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
 endif
 endif
diff --git a/Makefile.objs b/Makefile.objs
index 7ce2588b89..98383972ee 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -125,6 +125,7 @@ trace-events-subdirs =
 trace-events-subdirs += accel/kvm
 trace-events-subdirs += accel/tcg
 trace-events-subdirs += backends
+trace-events-subdirs += backends/tpm
 trace-events-subdirs += crypto
 trace-events-subdirs += monitor
 ifeq ($(CONFIG_USER_ONLY),y)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index f24d7da783..d54a8701d8 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -101,7 +101,7 @@ struct KVMState
     bool kernel_irqchip_required;
     OnOffAuto kernel_irqchip_split;
     bool sync_mmu;
-    bool manual_dirty_log_protect;
+    uint64_t manual_dirty_log_protect;
     /* The man page (and posix) say ioctl numbers are signed int, but
      * they're not.  Linux, glibc and *BSD all treat ioctl numbers as
      * unsigned, and treating them as signed here can break things */
@@ -1995,6 +1995,7 @@ static int kvm_init(MachineState *ms)
     int ret;
     int type = 0;
     const char *kvm_type;
+    uint64_t dirty_log_manual_caps;
 
     s = KVM_STATE(ms->accelerator);
 
@@ -2120,14 +2121,20 @@ static int kvm_init(MachineState *ms)
     s->coalesced_pio = s->coalesced_mmio &&
                        kvm_check_extension(s, KVM_CAP_COALESCED_PIO);
 
-    s->manual_dirty_log_protect =
+    dirty_log_manual_caps =
         kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
-    if (s->manual_dirty_log_protect) {
-        ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0, 1);
+    dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
+                              KVM_DIRTY_LOG_INITIALLY_SET);
+    s->manual_dirty_log_protect = dirty_log_manual_caps;
+    if (dirty_log_manual_caps) {
+        ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
+                                   dirty_log_manual_caps);
         if (ret) {
-            warn_report("Trying to enable KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 "
-                        "but failed.  Falling back to the legacy mode. ");
-            s->manual_dirty_log_protect = false;
+            warn_report("Trying to enable capability %"PRIu64" of "
+                        "KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
+                        "Falling back to the legacy mode. ",
+                        dirty_log_manual_caps);
+            s->manual_dirty_log_protect = 0;
         }
     }
 
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index c3d37058a1..2afa46bd2b 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -2582,9 +2582,9 @@ int page_check_range(target_ulong start, target_ulong 
len, int flags)
     /* This function should never be called with addresses outside the
        guest address space.  If this assert fires, it probably indicates
        a missing call to h2g_valid.  */
-#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
-    assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
-#endif
+    if (TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS) {
+        assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
+    }
 
     if (len == 0) {
         return 0;
diff --git a/backends/Kconfig b/backends/Kconfig
new file mode 100644
index 0000000000..f35abc1609
--- /dev/null
+++ b/backends/Kconfig
@@ -0,0 +1 @@
+source tpm/Kconfig
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 28a847cd57..22d204cb48 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -1,7 +1,7 @@
 common-obj-y += rng.o rng-egd.o rng-builtin.o
 common-obj-$(CONFIG_POSIX) += rng-random.o
 
-common-obj-$(CONFIG_TPM) += tpm.o
+common-obj-$(CONFIG_TPM) += tpm/
 
 common-obj-y += hostmem.o hostmem-ram.o
 common-obj-$(CONFIG_POSIX) += hostmem-file.o
diff --git a/backends/tpm.c b/backends/tpm.c
deleted file mode 100644
index 375587e743..0000000000
--- a/backends/tpm.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * QEMU TPM Backend
- *
- * Copyright IBM, Corp. 2013
- *
- * Authors:
- *  Stefan Berger   <stefanb@xxxxxxxxxx>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * Based on backends/rng.c by Anthony Liguori
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/tpm_backend.h"
-#include "qapi/error.h"
-#include "sysemu/tpm.h"
-#include "qemu/thread.h"
-#include "qemu/main-loop.h"
-#include "qemu/module.h"
-#include "block/thread-pool.h"
-#include "qemu/error-report.h"
-
-static void tpm_backend_request_completed(void *opaque, int ret)
-{
-    TPMBackend *s = TPM_BACKEND(opaque);
-    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
-
-    tic->request_completed(s->tpmif, ret);
-
-    /* no need for atomic, as long the BQL is taken */
-    s->cmd = NULL;
-    object_unref(OBJECT(s));
-}
-
-static int tpm_backend_worker_thread(gpointer data)
-{
-    TPMBackend *s = TPM_BACKEND(data);
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-    Error *err = NULL;
-
-    k->handle_request(s, s->cmd, &err);
-    if (err) {
-        error_report_err(err);
-        return -1;
-    }
-
-    return 0;
-}
-
-void tpm_backend_finish_sync(TPMBackend *s)
-{
-    while (s->cmd) {
-        aio_poll(qemu_get_aio_context(), true);
-    }
-}
-
-enum TpmType tpm_backend_get_type(TPMBackend *s)
-{
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    return k->type;
-}
-
-int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp)
-{
-    if (s->tpmif) {
-        error_setg(errp, "TPM backend '%s' is already initialized", s->id);
-        return -1;
-    }
-
-    s->tpmif = tpmif;
-    object_ref(OBJECT(tpmif));
-
-    s->had_startup_error = false;
-
-    return 0;
-}
-
-int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize)
-{
-    int res = 0;
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    /* terminate a running TPM */
-    tpm_backend_finish_sync(s);
-
-    res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0;
-
-    s->had_startup_error = (res != 0);
-
-    return res;
-}
-
-bool tpm_backend_had_startup_error(TPMBackend *s)
-{
-    return s->had_startup_error;
-}
-
-void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
-{
-    ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
-
-    if (s->cmd != NULL) {
-        error_report("There is a TPM request pending");
-        return;
-    }
-
-    s->cmd = cmd;
-    object_ref(OBJECT(s));
-    thread_pool_submit_aio(pool, tpm_backend_worker_thread, s,
-                           tpm_backend_request_completed, s);
-}
-
-void tpm_backend_reset(TPMBackend *s)
-{
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    if (k->reset) {
-        k->reset(s);
-    }
-
-    tpm_backend_finish_sync(s);
-
-    s->had_startup_error = false;
-}
-
-void tpm_backend_cancel_cmd(TPMBackend *s)
-{
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    k->cancel_cmd(s);
-}
-
-bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
-{
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    return k->get_tpm_established_flag ?
-           k->get_tpm_established_flag(s) : false;
-}
-
-int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
-{
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    return k->reset_tpm_established_flag ?
-           k->reset_tpm_established_flag(s, locty) : 0;
-}
-
-TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
-{
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    return k->get_tpm_version(s);
-}
-
-size_t tpm_backend_get_buffer_size(TPMBackend *s)
-{
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
-    return k->get_buffer_size(s);
-}
-
-TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
-{
-    TPMInfo *info = g_new0(TPMInfo, 1);
-    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
-
-    info->id = g_strdup(s->id);
-    info->model = tic->model;
-    info->options = k->get_tpm_options(s);
-
-    return info;
-}
-
-static void tpm_backend_instance_finalize(Object *obj)
-{
-    TPMBackend *s = TPM_BACKEND(obj);
-
-    object_unref(OBJECT(s->tpmif));
-    g_free(s->id);
-}
-
-static const TypeInfo tpm_backend_info = {
-    .name = TYPE_TPM_BACKEND,
-    .parent = TYPE_OBJECT,
-    .instance_size = sizeof(TPMBackend),
-    .instance_finalize = tpm_backend_instance_finalize,
-    .class_size = sizeof(TPMBackendClass),
-    .abstract = true,
-};
-
-static const TypeInfo tpm_if_info = {
-    .name = TYPE_TPM_IF,
-    .parent = TYPE_INTERFACE,
-    .class_size = sizeof(TPMIfClass),
-};
-
-static void register_types(void)
-{
-    type_register_static(&tpm_backend_info);
-    type_register_static(&tpm_if_info);
-}
-
-type_init(register_types);
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
new file mode 100644
index 0000000000..5d91eb89c2
--- /dev/null
+++ b/backends/tpm/Kconfig
@@ -0,0 +1,14 @@
+config TPM_BACKEND
+    bool
+    depends on TPM
+
+config TPM_PASSTHROUGH
+    bool
+    default y
+    # FIXME: should check for x86 host as well
+    depends on TPM_BACKEND && LINUX
+
+config TPM_EMULATOR
+    bool
+    default y
+    depends on TPM_BACKEND
diff --git a/backends/tpm/Makefile.objs b/backends/tpm/Makefile.objs
new file mode 100644
index 0000000000..db2731f634
--- /dev/null
+++ b/backends/tpm/Makefile.objs
@@ -0,0 +1,4 @@
+common-obj-y += tpm_backend.o
+common-obj-y += tpm_util.o
+common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
+common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
diff --git a/backends/tpm/tpm_backend.c b/backends/tpm/tpm_backend.c
new file mode 100644
index 0000000000..375587e743
--- /dev/null
+++ b/backends/tpm/tpm_backend.c
@@ -0,0 +1,208 @@
+/*
+ * QEMU TPM Backend
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ *  Stefan Berger   <stefanb@xxxxxxxxxx>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Based on backends/rng.c by Anthony Liguori
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/tpm_backend.h"
+#include "qapi/error.h"
+#include "sysemu/tpm.h"
+#include "qemu/thread.h"
+#include "qemu/main-loop.h"
+#include "qemu/module.h"
+#include "block/thread-pool.h"
+#include "qemu/error-report.h"
+
+static void tpm_backend_request_completed(void *opaque, int ret)
+{
+    TPMBackend *s = TPM_BACKEND(opaque);
+    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
+
+    tic->request_completed(s->tpmif, ret);
+
+    /* no need for atomic, as long the BQL is taken */
+    s->cmd = NULL;
+    object_unref(OBJECT(s));
+}
+
+static int tpm_backend_worker_thread(gpointer data)
+{
+    TPMBackend *s = TPM_BACKEND(data);
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+    Error *err = NULL;
+
+    k->handle_request(s, s->cmd, &err);
+    if (err) {
+        error_report_err(err);
+        return -1;
+    }
+
+    return 0;
+}
+
+void tpm_backend_finish_sync(TPMBackend *s)
+{
+    while (s->cmd) {
+        aio_poll(qemu_get_aio_context(), true);
+    }
+}
+
+enum TpmType tpm_backend_get_type(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->type;
+}
+
+int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp)
+{
+    if (s->tpmif) {
+        error_setg(errp, "TPM backend '%s' is already initialized", s->id);
+        return -1;
+    }
+
+    s->tpmif = tpmif;
+    object_ref(OBJECT(tpmif));
+
+    s->had_startup_error = false;
+
+    return 0;
+}
+
+int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize)
+{
+    int res = 0;
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    /* terminate a running TPM */
+    tpm_backend_finish_sync(s);
+
+    res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0;
+
+    s->had_startup_error = (res != 0);
+
+    return res;
+}
+
+bool tpm_backend_had_startup_error(TPMBackend *s)
+{
+    return s->had_startup_error;
+}
+
+void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
+{
+    ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
+
+    if (s->cmd != NULL) {
+        error_report("There is a TPM request pending");
+        return;
+    }
+
+    s->cmd = cmd;
+    object_ref(OBJECT(s));
+    thread_pool_submit_aio(pool, tpm_backend_worker_thread, s,
+                           tpm_backend_request_completed, s);
+}
+
+void tpm_backend_reset(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    if (k->reset) {
+        k->reset(s);
+    }
+
+    tpm_backend_finish_sync(s);
+
+    s->had_startup_error = false;
+}
+
+void tpm_backend_cancel_cmd(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    k->cancel_cmd(s);
+}
+
+bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->get_tpm_established_flag ?
+           k->get_tpm_established_flag(s) : false;
+}
+
+int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->reset_tpm_established_flag ?
+           k->reset_tpm_established_flag(s, locty) : 0;
+}
+
+TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->get_tpm_version(s);
+}
+
+size_t tpm_backend_get_buffer_size(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->get_buffer_size(s);
+}
+
+TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
+{
+    TPMInfo *info = g_new0(TPMInfo, 1);
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
+
+    info->id = g_strdup(s->id);
+    info->model = tic->model;
+    info->options = k->get_tpm_options(s);
+
+    return info;
+}
+
+static void tpm_backend_instance_finalize(Object *obj)
+{
+    TPMBackend *s = TPM_BACKEND(obj);
+
+    object_unref(OBJECT(s->tpmif));
+    g_free(s->id);
+}
+
+static const TypeInfo tpm_backend_info = {
+    .name = TYPE_TPM_BACKEND,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(TPMBackend),
+    .instance_finalize = tpm_backend_instance_finalize,
+    .class_size = sizeof(TPMBackendClass),
+    .abstract = true,
+};
+
+static const TypeInfo tpm_if_info = {
+    .name = TYPE_TPM_IF,
+    .parent = TYPE_INTERFACE,
+    .class_size = sizeof(TPMIfClass),
+};
+
+static void register_types(void)
+{
+    type_register_static(&tpm_backend_info);
+    type_register_static(&tpm_if_info);
+}
+
+type_init(register_types);
diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
new file mode 100644
index 0000000000..9605339f93
--- /dev/null
+++ b/backends/tpm/tpm_emulator.c
@@ -0,0 +1,997 @@
+/*
+ *  Emulator TPM driver
+ *
+ *  Copyright (c) 2017 Intel Corporation
+ *  Author: Amarnath Valluri <amarnath.valluri@xxxxxxxxx>
+ *
+ *  Copyright (c) 2010 - 2013, 2018 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@xxxxxxxxxx>
+ *
+ *  Copyright (C) 2011 IAIK, Graz University of Technology
+ *    Author: Andreas Niederl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "qemu/sockets.h"
+#include "io/channel-socket.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+#include "tpm_int.h"
+#include "tpm_ioctl.h"
+#include "migration/blocker.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+#include "chardev/char-fe.h"
+#include "trace.h"
+
+#define TYPE_TPM_EMULATOR "tpm-emulator"
+#define TPM_EMULATOR(obj) \
+    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
+
+#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
+
+/* data structures */
+
+/* blobs from the TPM; part of VM state when migrating */
+typedef struct TPMBlobBuffers {
+    uint32_t permanent_flags;
+    TPMSizedBuffer permanent;
+
+    uint32_t volatil_flags;
+    TPMSizedBuffer volatil;
+
+    uint32_t savestate_flags;
+    TPMSizedBuffer savestate;
+} TPMBlobBuffers;
+
+typedef struct TPMEmulator {
+    TPMBackend parent;
+
+    TPMEmulatorOptions *options;
+    CharBackend ctrl_chr;
+    QIOChannel *data_ioc;
+    TPMVersion tpm_version;
+    ptm_cap caps; /* capabilities of the TPM */
+    uint8_t cur_locty_number; /* last set locality */
+    Error *migration_blocker;
+
+    QemuMutex mutex;
+
+    unsigned int established_flag:1;
+    unsigned int established_flag_cached:1;
+
+    TPMBlobBuffers state_blobs;
+} TPMEmulator;
+
+struct tpm_error {
+    uint32_t tpm_result;
+    const char *string;
+};
+
+static const struct tpm_error tpm_errors[] = {
+    /* TPM 1.2 error codes */
+    { TPM_BAD_PARAMETER   , "a parameter is bad" },
+    { TPM_FAIL            , "operation failed" },
+    { TPM_KEYNOTFOUND     , "key could not be found" },
+    { TPM_BAD_PARAM_SIZE  , "bad parameter size"},
+    { TPM_ENCRYPT_ERROR   , "encryption error" },
+    { TPM_DECRYPT_ERROR   , "decryption error" },
+    { TPM_BAD_KEY_PROPERTY, "bad key property" },
+    { TPM_BAD_MODE        , "bad (encryption) mode" },
+    { TPM_BAD_VERSION     , "bad version identifier" },
+    { TPM_BAD_LOCALITY    , "bad locality" },
+    /* TPM 2 error codes */
+    { TPM_RC_FAILURE     , "operation failed" },
+    { TPM_RC_LOCALITY    , "bad locality"     },
+    { TPM_RC_INSUFFICIENT, "insufficient amount of data" },
+};
+
+static const char *tpm_emulator_strerror(uint32_t tpm_result)
+{
+    size_t i;
+
+    for (i = 0; i < ARRAY_SIZE(tpm_errors); i++) {
+        if (tpm_errors[i].tpm_result == tpm_result) {
+            return tpm_errors[i].string;
+        }
+    }
+    return "";
+}
+
+static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
+                                size_t msg_len_in, size_t msg_len_out)
+{
+    CharBackend *dev = &tpm->ctrl_chr;
+    uint32_t cmd_no = cpu_to_be32(cmd);
+    ssize_t n = sizeof(uint32_t) + msg_len_in;
+    uint8_t *buf = NULL;
+    int ret = -1;
+
+    qemu_mutex_lock(&tpm->mutex);
+
+    buf = g_alloca(n);
+    memcpy(buf, &cmd_no, sizeof(cmd_no));
+    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
+
+    n = qemu_chr_fe_write_all(dev, buf, n);
+    if (n <= 0) {
+        goto end;
+    }
+
+    if (msg_len_out != 0) {
+        n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
+        if (n <= 0) {
+            goto end;
+        }
+    }
+
+    ret = 0;
+
+end:
+    qemu_mutex_unlock(&tpm->mutex);
+    return ret;
+}
+
+static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
+                                     const uint8_t *in, uint32_t in_len,
+                                     uint8_t *out, uint32_t out_len,
+                                     bool *selftest_done,
+                                     Error **errp)
+{
+    ssize_t ret;
+    bool is_selftest = false;
+
+    if (selftest_done) {
+        *selftest_done = false;
+        is_selftest = tpm_util_is_selftest(in, in_len);
+    }
+
+    ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp);
+    if (ret != 0) {
+        return -1;
+    }
+
+    ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out,
+              sizeof(struct tpm_resp_hdr), errp);
+    if (ret != 0) {
+        return -1;
+    }
+
+    ret = qio_channel_read_all(tpm_emu->data_ioc,
+              (char *)out + sizeof(struct tpm_resp_hdr),
+              tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp);
+    if (ret != 0) {
+        return -1;
+    }
+
+    if (is_selftest) {
+        *selftest_done = tpm_cmd_get_errcode(out) == 0;
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t 
locty_number,
+                                     Error **errp)
+{
+    ptm_loc loc;
+
+    if (tpm_emu->cur_locty_number == locty_number) {
+        return 0;
+    }
+
+    trace_tpm_emulator_set_locality(locty_number);
+
+    memset(&loc, 0, sizeof(loc));
+    loc.u.req.loc = locty_number;
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc,
+                             sizeof(loc), sizeof(loc)) < 0) {
+        error_setg(errp, "tpm-emulator: could not set locality : %s",
+                   strerror(errno));
+        return -1;
+    }
+
+    loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
+    if (loc.u.resp.tpm_result != 0) {
+        error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x",
+                   loc.u.resp.tpm_result);
+        return -1;
+    }
+
+    tpm_emu->cur_locty_number = locty_number;
+
+    return 0;
+}
+
+static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
+                                        Error **errp)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+    trace_tpm_emulator_handle_request();
+
+    if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 ||
+        tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len,
+                                  cmd->out, cmd->out_len,
+                                  &cmd->selftest_done, errp) < 0) {
+        tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
+    }
+}
+
+static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
+{
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY,
+                             &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
+        error_report("tpm-emulator: probing failed : %s", strerror(errno));
+        return -1;
+    }
+
+    tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
+
+    trace_tpm_emulator_probe_caps(tpm_emu->caps);
+
+    return 0;
+}
+
+static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
+{
+    ptm_cap caps = 0;
+    const char *tpm = NULL;
+
+    /* check for min. required capabilities */
+    switch (tpm_emu->tpm_version) {
+    case TPM_VERSION_1_2:
+        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+               PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP |
+               PTM_CAP_SET_BUFFERSIZE;
+        tpm = "1.2";
+        break;
+    case TPM_VERSION_2_0:
+        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
+               PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
+        tpm = "2";
+        break;
+    case TPM_VERSION_UNSPEC:
+        error_report("tpm-emulator: TPM version has not been set");
+        return -1;
+    }
+
+    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
+        error_report("tpm-emulator: TPM does not implement minimum set of "
+                     "required capabilities for TPM %s (0x%x)", tpm, 
(int)caps);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_stop_tpm(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_res res;
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
+        error_report("tpm-emulator: Could not stop TPM: %s",
+                     strerror(errno));
+        return -1;
+    }
+
+    res = be32_to_cpu(res);
+    if (res) {
+        error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x %s", res,
+                     tpm_emulator_strerror(res));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_set_buffer_size(TPMBackend *tb,
+                                        size_t wanted_size,
+                                        size_t *actual_size)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_setbuffersize psbs;
+
+    if (tpm_emulator_stop_tpm(tb) < 0) {
+        return -1;
+    }
+
+    psbs.u.req.buffersize = cpu_to_be32(wanted_size);
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
+                             sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
+        error_report("tpm-emulator: Could not set buffer size: %s",
+                     strerror(errno));
+        return -1;
+    }
+
+    psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result);
+    if (psbs.u.resp.tpm_result != 0) {
+        error_report("tpm-emulator: TPM result for set buffer size : 0x%x %s",
+                     psbs.u.resp.tpm_result,
+                     tpm_emulator_strerror(psbs.u.resp.tpm_result));
+        return -1;
+    }
+
+    if (actual_size) {
+        *actual_size = be32_to_cpu(psbs.u.resp.buffersize);
+    }
+
+    trace_tpm_emulator_set_buffer_size(
+            be32_to_cpu(psbs.u.resp.buffersize),
+            be32_to_cpu(psbs.u.resp.minsize),
+            be32_to_cpu(psbs.u.resp.maxsize));
+
+    return 0;
+}
+
+static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize,
+                                     bool is_resume)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_init init = {
+        .u.req.init_flags = 0,
+    };
+    ptm_res res;
+
+    trace_tpm_emulator_startup_tpm_resume(is_resume, buffersize);
+
+    if (buffersize != 0 &&
+        tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
+        goto err_exit;
+    }
+
+    if (is_resume) {
+        init.u.req.init_flags |= cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE);
+    }
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
+                             sizeof(init)) < 0) {
+        error_report("tpm-emulator: could not send INIT: %s",
+                     strerror(errno));
+        goto err_exit;
+    }
+
+    res = be32_to_cpu(init.u.resp.tpm_result);
+    if (res) {
+        error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x %s", res,
+                     tpm_emulator_strerror(res));
+        goto err_exit;
+    }
+    return 0;
+
+err_exit:
+    return -1;
+}
+
+static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
+{
+    return tpm_emulator_startup_tpm_resume(tb, buffersize, false);
+}
+
+static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_est est;
+
+    if (tpm_emu->established_flag_cached) {
+        return tpm_emu->established_flag;
+    }
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est,
+                             0, sizeof(est)) < 0) {
+        error_report("tpm-emulator: Could not get the TPM established flag: 
%s",
+                     strerror(errno));
+        return false;
+    }
+    trace_tpm_emulator_get_tpm_established_flag(est.u.resp.bit);
+
+    tpm_emu->established_flag_cached = 1;
+    tpm_emu->established_flag = (est.u.resp.bit != 0);
+
+    return tpm_emu->established_flag;
+}
+
+static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
+                                                   uint8_t locty)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_reset_est reset_est;
+    ptm_res res;
+
+    /* only a TPM 2.0 will support this */
+    if (tpm_emu->tpm_version != TPM_VERSION_2_0) {
+        return 0;
+    }
+
+    reset_est.u.req.loc = tpm_emu->cur_locty_number;
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED,
+                             &reset_est, sizeof(reset_est),
+                             sizeof(reset_est)) < 0) {
+        error_report("tpm-emulator: Could not reset the establishment bit: %s",
+                     strerror(errno));
+        return -1;
+    }
+
+    res = be32_to_cpu(reset_est.u.resp.tpm_result);
+    if (res) {
+        error_report(
+            "tpm-emulator: TPM result for rest established flag: 0x%x %s",
+            res, tpm_emulator_strerror(res));
+        return -1;
+    }
+
+    tpm_emu->established_flag_cached = 0;
+
+    return 0;
+}
+
+static void tpm_emulator_cancel_cmd(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    ptm_res res;
+
+    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) {
+        trace_tpm_emulator_cancel_cmd_not_supt();
+        return;
+    }
+
+    /* FIXME: make the function non-blocking, or it may block a VCPU */
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
+                             sizeof(res)) < 0) {
+        error_report("tpm-emulator: Could not cancel command: %s",
+                     strerror(errno));
+    } else if (res != 0) {
+        error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
+                     be32_to_cpu(res));
+    }
+}
+
+static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+    return tpm_emu->tpm_version;
+}
+
+static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
+{
+    size_t actual_size;
+
+    if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) {
+        return 4096;
+    }
+
+    return actual_size;
+}
+
+static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
+{
+    Error *err = NULL;
+    ptm_cap caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB |
+                   PTM_CAP_STOP;
+
+    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
+        error_setg(&tpm_emu->migration_blocker,
+                   "Migration disabled: TPM emulator does not support "
+                   "migration");
+        migrate_add_blocker(tpm_emu->migration_blocker, &err);
+        if (err) {
+            error_report_err(err);
+            error_free(tpm_emu->migration_blocker);
+            tpm_emu->migration_blocker = NULL;
+
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
+{
+    ptm_res res;
+    Error *err = NULL;
+    int fds[2] = { -1, -1 };
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
+        error_report("tpm-emulator: Failed to create socketpair");
+        return -1;
+    }
+
+    qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0,
+                             sizeof(res)) < 0 || res != 0) {
+        error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
+                     strerror(errno));
+        goto err_exit;
+    }
+
+    tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));
+    if (err) {
+        error_prepend(&err, "tpm-emulator: Failed to create io channel: ");
+        error_report_err(err);
+        goto err_exit;
+    }
+
+    closesocket(fds[1]);
+
+    return 0;
+
+err_exit:
+    closesocket(fds[0]);
+    closesocket(fds[1]);
+    return -1;
+}
+
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+{
+    const char *value;
+
+    value = qemu_opt_get(opts, "chardev");
+    if (value) {
+        Error *err = NULL;
+        Chardev *dev = qemu_chr_find(value);
+
+        if (!dev) {
+            error_report("tpm-emulator: tpm chardev '%s' not found.", value);
+            goto err;
+        }
+
+        if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
+            error_prepend(&err, "tpm-emulator: No valid chardev found at 
'%s':",
+                          value);
+            error_report_err(err);
+            goto err;
+        }
+
+        tpm_emu->options->chardev = g_strdup(value);
+    }
+
+    if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
+        goto err;
+    }
+
+    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
+     * by passthrough driver, which not yet using GIOChannel.
+     */
+    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
+                             &tpm_emu->tpm_version)) {
+        error_report("'%s' is not emulating TPM device. Error: %s",
+                      tpm_emu->options->chardev, strerror(errno));
+        goto err;
+    }
+
+    switch (tpm_emu->tpm_version) {
+    case TPM_VERSION_1_2:
+        trace_tpm_emulator_handle_device_opts_tpm12();
+        break;
+    case TPM_VERSION_2_0:
+        trace_tpm_emulator_handle_device_opts_tpm2();
+        break;
+    default:
+        trace_tpm_emulator_handle_device_opts_unspec();
+    }
+
+    if (tpm_emulator_probe_caps(tpm_emu) ||
+        tpm_emulator_check_caps(tpm_emu)) {
+        goto err;
+    }
+
+    return tpm_emulator_block_migration(tpm_emu);
+
+err:
+    trace_tpm_emulator_handle_device_opts_startup_error();
+
+    return -1;
+}
+
+static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+{
+    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
+
+    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
+        object_unref(OBJECT(tb));
+        return NULL;
+    }
+
+    return tb;
+}
+
+static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
+
+    options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
+    options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, 
tpm_emu->options);
+
+    return options;
+}
+
+static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {
+        .name = "chardev",
+        .type = QEMU_OPT_STRING,
+        .help = "Character device to use for out-of-band control messages",
+    },
+    { /* end of list */ },
+};
+
+/*
+ * Transfer a TPM state blob from the TPM into a provided buffer.
+ *
+ * @tpm_emu: TPMEmulator
+ * @type: the type of blob to transfer
+ * @tsb: the TPMSizeBuffer to fill with the blob
+ * @flags: the flags to return to the caller
+ */
+static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu,
+                                       uint8_t type,
+                                       TPMSizedBuffer *tsb,
+                                       uint32_t *flags)
+{
+    ptm_getstate pgs;
+    ptm_res res;
+    ssize_t n;
+    uint32_t totlength, length;
+
+    tpm_sized_buffer_reset(tsb);
+
+    pgs.u.req.state_flags = cpu_to_be32(PTM_STATE_FLAG_DECRYPTED);
+    pgs.u.req.type = cpu_to_be32(type);
+    pgs.u.req.offset = 0;
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB,
+                             &pgs, sizeof(pgs.u.req),
+                             offsetof(ptm_getstate, u.resp.data)) < 0) {
+        error_report("tpm-emulator: could not get state blob type %d : %s",
+                     type, strerror(errno));
+        return -1;
+    }
+
+    res = be32_to_cpu(pgs.u.resp.tpm_result);
+    if (res != 0 && (res & 0x800) == 0) {
+        error_report("tpm-emulator: Getting the stateblob (type %d) failed "
+                     "with a TPM error 0x%x %s", type, res,
+                     tpm_emulator_strerror(res));
+        return -1;
+    }
+
+    totlength = be32_to_cpu(pgs.u.resp.totlength);
+    length = be32_to_cpu(pgs.u.resp.length);
+    if (totlength != length) {
+        error_report("tpm-emulator: Expecting to read %u bytes "
+                     "but would get %u", totlength, length);
+        return -1;
+    }
+
+    *flags = be32_to_cpu(pgs.u.resp.state_flags);
+
+    if (totlength > 0) {
+        tsb->buffer = g_try_malloc(totlength);
+        if (!tsb->buffer) {
+            error_report("tpm-emulator: Out of memory allocating %u bytes",
+                         totlength);
+            return -1;
+        }
+
+        n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, tsb->buffer, totlength);
+        if (n != totlength) {
+            error_report("tpm-emulator: Could not read stateblob (type %d); "
+                         "expected %u bytes, got %zd",
+                         type, totlength, n);
+            return -1;
+        }
+    }
+    tsb->size = totlength;
+
+    trace_tpm_emulator_get_state_blob(type, tsb->size, *flags);
+
+    return 0;
+}
+
+static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu)
+{
+    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+    if (tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
+                                    &state_blobs->permanent,
+                                    &state_blobs->permanent_flags) < 0 ||
+        tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
+                                    &state_blobs->volatil,
+                                    &state_blobs->volatil_flags) < 0 ||
+        tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
+                                    &state_blobs->savestate,
+                                    &state_blobs->savestate_flags) < 0) {
+        goto err_exit;
+    }
+
+    return 0;
+
+ err_exit:
+    tpm_sized_buffer_reset(&state_blobs->volatil);
+    tpm_sized_buffer_reset(&state_blobs->permanent);
+    tpm_sized_buffer_reset(&state_blobs->savestate);
+
+    return -1;
+}
+
+/*
+ * Transfer a TPM state blob to the TPM emulator.
+ *
+ * @tpm_emu: TPMEmulator
+ * @type: the type of TPM state blob to transfer
+ * @tsb: TPMSizedBuffer containing the TPM state blob
+ * @flags: Flags describing the (encryption) state of the TPM state blob
+ */
+static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
+                                       uint32_t type,
+                                       TPMSizedBuffer *tsb,
+                                       uint32_t flags)
+{
+    ssize_t n;
+    ptm_setstate pss;
+    ptm_res tpm_result;
+
+    if (tsb->size == 0) {
+        return 0;
+    }
+
+    pss = (ptm_setstate) {
+        .u.req.state_flags = cpu_to_be32(flags),
+        .u.req.type = cpu_to_be32(type),
+        .u.req.length = cpu_to_be32(tsb->size),
+    };
+
+    /* write the header only */
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss,
+                             offsetof(ptm_setstate, u.req.data), 0) < 0) {
+        error_report("tpm-emulator: could not set state blob type %d : %s",
+                     type, strerror(errno));
+        return -1;
+    }
+
+    /* now the body */
+    n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size);
+    if (n != tsb->size) {
+        error_report("tpm-emulator: Writing the stateblob (type %d) "
+                     "failed; could not write %u bytes, but only %zd",
+                     type, tsb->size, n);
+        return -1;
+    }
+
+    /* now get the result */
+    n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr,
+                             (uint8_t *)&pss, sizeof(pss.u.resp));
+    if (n != sizeof(pss.u.resp)) {
+        error_report("tpm-emulator: Reading response from writing stateblob "
+                     "(type %d) failed; expected %zu bytes, got %zd", type,
+                     sizeof(pss.u.resp), n);
+        return -1;
+    }
+
+    tpm_result = be32_to_cpu(pss.u.resp.tpm_result);
+    if (tpm_result != 0) {
+        error_report("tpm-emulator: Setting the stateblob (type %d) failed "
+                     "with a TPM error 0x%x %s", type, tpm_result,
+                     tpm_emulator_strerror(tpm_result));
+        return -1;
+    }
+
+    trace_tpm_emulator_set_state_blob(type, tsb->size, flags);
+
+    return 0;
+}
+
+/*
+ * Set all the TPM state blobs.
+ *
+ * Returns a negative errno code in case of error.
+ */
+static int tpm_emulator_set_state_blobs(TPMBackend *tb)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+    trace_tpm_emulator_set_state_blobs();
+
+    if (tpm_emulator_stop_tpm(tb) < 0) {
+        trace_tpm_emulator_set_state_blobs_error("Could not stop TPM");
+        return -EIO;
+    }
+
+    if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
+                                    &state_blobs->permanent,
+                                    state_blobs->permanent_flags) < 0 ||
+        tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
+                                    &state_blobs->volatil,
+                                    state_blobs->volatil_flags) < 0 ||
+        tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
+                                    &state_blobs->savestate,
+                                    state_blobs->savestate_flags) < 0) {
+        return -EIO;
+    }
+
+    trace_tpm_emulator_set_state_blobs_done();
+
+    return 0;
+}
+
+static int tpm_emulator_pre_save(void *opaque)
+{
+    TPMBackend *tb = opaque;
+    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+    trace_tpm_emulator_pre_save();
+
+    tpm_backend_finish_sync(tb);
+
+    /* get the state blobs from the TPM */
+    return tpm_emulator_get_state_blobs(tpm_emu);
+}
+
+/*
+ * Load the TPM state blobs into the TPM.
+ *
+ * Returns negative errno codes in case of error.
+ */
+static int tpm_emulator_post_load(void *opaque, int version_id)
+{
+    TPMBackend *tb = opaque;
+    int ret;
+
+    ret = tpm_emulator_set_state_blobs(tb);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (tpm_emulator_startup_tpm_resume(tb, 0, true) < 0) {
+        return -EIO;
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_tpm_emulator = {
+    .name = "tpm-emulator",
+    .version_id = 0,
+    .pre_save = tpm_emulator_pre_save,
+    .post_load = tpm_emulator_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator),
+        VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator),
+        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.permanent.buffer,
+                                     TPMEmulator, 0, 0,
+                                     state_blobs.permanent.size),
+
+        VMSTATE_UINT32(state_blobs.volatil_flags, TPMEmulator),
+        VMSTATE_UINT32(state_blobs.volatil.size, TPMEmulator),
+        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.volatil.buffer,
+                                     TPMEmulator, 0, 0,
+                                     state_blobs.volatil.size),
+
+        VMSTATE_UINT32(state_blobs.savestate_flags, TPMEmulator),
+        VMSTATE_UINT32(state_blobs.savestate.size, TPMEmulator),
+        VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.savestate.buffer,
+                                     TPMEmulator, 0, 0,
+                                     state_blobs.savestate.size),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tpm_emulator_inst_init(Object *obj)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
+
+    trace_tpm_emulator_inst_init();
+
+    tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
+    tpm_emu->cur_locty_number = ~0;
+    qemu_mutex_init(&tpm_emu->mutex);
+
+    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
+                     &vmstate_tpm_emulator, obj);
+}
+
+/*
+ * Gracefully shut down the external TPM
+ */
+static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
+{
+    ptm_res res;
+
+    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) 
{
+        error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
+                     strerror(errno));
+    } else if (res != 0) {
+        error_report("tpm-emulator: TPM result for shutdown: 0x%x %s",
+                     be32_to_cpu(res), 
tpm_emulator_strerror(be32_to_cpu(res)));
+    }
+}
+
+static void tpm_emulator_inst_finalize(Object *obj)
+{
+    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
+    TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+    tpm_emulator_shutdown(tpm_emu);
+
+    object_unref(OBJECT(tpm_emu->data_ioc));
+
+    qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false);
+
+    qapi_free_TPMEmulatorOptions(tpm_emu->options);
+
+    if (tpm_emu->migration_blocker) {
+        migrate_del_blocker(tpm_emu->migration_blocker);
+        error_free(tpm_emu->migration_blocker);
+    }
+
+    tpm_sized_buffer_reset(&state_blobs->volatil);
+    tpm_sized_buffer_reset(&state_blobs->permanent);
+    tpm_sized_buffer_reset(&state_blobs->savestate);
+
+    qemu_mutex_destroy(&tpm_emu->mutex);
+
+    vmstate_unregister(NULL, &vmstate_tpm_emulator, obj);
+}
+
+static void tpm_emulator_class_init(ObjectClass *klass, void *data)
+{
+    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+
+    tbc->type = TPM_TYPE_EMULATOR;
+    tbc->opts = tpm_emulator_cmdline_opts;
+    tbc->desc = "TPM emulator backend driver";
+    tbc->create = tpm_emulator_create;
+    tbc->startup_tpm = tpm_emulator_startup_tpm;
+    tbc->cancel_cmd = tpm_emulator_cancel_cmd;
+    tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
+    tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
+    tbc->get_tpm_version = tpm_emulator_get_tpm_version;
+    tbc->get_buffer_size = tpm_emulator_get_buffer_size;
+    tbc->get_tpm_options = tpm_emulator_get_tpm_options;
+
+    tbc->handle_request = tpm_emulator_handle_request;
+}
+
+static const TypeInfo tpm_emulator_info = {
+    .name = TYPE_TPM_EMULATOR,
+    .parent = TYPE_TPM_BACKEND,
+    .instance_size = sizeof(TPMEmulator),
+    .class_init = tpm_emulator_class_init,
+    .instance_init = tpm_emulator_inst_init,
+    .instance_finalize = tpm_emulator_inst_finalize,
+};
+
+static void tpm_emulator_register(void)
+{
+    type_register_static(&tpm_emulator_info);
+}
+
+type_init(tpm_emulator_register)
diff --git a/backends/tpm/tpm_int.h b/backends/tpm/tpm_int.h
new file mode 100644
index 0000000000..ba6109306e
--- /dev/null
+++ b/backends/tpm/tpm_int.h
@@ -0,0 +1,88 @@
+/*
+ * TPM configuration
+ *
+ * Copyright (C) 2011-2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@xxxxxxxxxx>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef BACKENDS_TPM_INT_H
+#define BACKENDS_TPM_INT_H
+
+#include "qemu/option.h"
+#include "sysemu/tpm.h"
+
+#define TPM_STANDARD_CMDLINE_OPTS \
+    { \
+        .name = "type", \
+        .type = QEMU_OPT_STRING, \
+        .help = "Type of TPM backend", \
+    }
+
+struct tpm_req_hdr {
+    uint16_t tag;
+    uint32_t len;
+    uint32_t ordinal;
+} QEMU_PACKED;
+
+struct tpm_resp_hdr {
+    uint16_t tag;
+    uint32_t len;
+    uint32_t errcode;
+} QEMU_PACKED;
+
+#define TPM_TAG_RQU_COMMAND       0xc1
+#define TPM_TAG_RQU_AUTH1_COMMAND 0xc2
+#define TPM_TAG_RQU_AUTH2_COMMAND 0xc3
+
+#define TPM_TAG_RSP_COMMAND       0xc4
+#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5
+#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6
+
+#define TPM_BAD_PARAMETER         3
+#define TPM_FAIL                  9
+#define TPM_KEYNOTFOUND           13
+#define TPM_BAD_PARAM_SIZE        25
+#define TPM_ENCRYPT_ERROR         32
+#define TPM_DECRYPT_ERROR         33
+#define TPM_BAD_KEY_PROPERTY      40
+#define TPM_BAD_MODE              44
+#define TPM_BAD_VERSION           46
+#define TPM_BAD_LOCALITY          61
+
+#define TPM_ORD_ContinueSelfTest  0x53
+#define TPM_ORD_GetTicks          0xf1
+#define TPM_ORD_GetCapability     0x65
+
+#define TPM_CAP_PROPERTY          0x05
+
+#define TPM_CAP_PROP_INPUT_BUFFER 0x124
+
+/* TPM2 defines */
+#define TPM2_ST_NO_SESSIONS       0x8001
+
+#define TPM2_CC_ReadClock         0x00000181
+#define TPM2_CC_GetCapability     0x0000017a
+
+#define TPM2_CAP_TPM_PROPERTIES   0x6
+
+#define TPM2_PT_MAX_COMMAND_SIZE  0x11e
+
+#define TPM_RC_INSUFFICIENT       0x9a
+#define TPM_RC_FAILURE            0x101
+#define TPM_RC_LOCALITY           0x907
+
+int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
+                             size_t *buffersize);
+
+typedef struct TPMSizedBuffer {
+    uint32_t size;
+    uint8_t  *buffer;
+} TPMSizedBuffer;
+
+void tpm_sized_buffer_reset(TPMSizedBuffer *tsb);
+
+#endif /* BACKENDS_TPM_INT_H */
diff --git a/backends/tpm/tpm_ioctl.h b/backends/tpm/tpm_ioctl.h
new file mode 100644
index 0000000000..f5f5c553a9
--- /dev/null
+++ b/backends/tpm/tpm_ioctl.h
@@ -0,0 +1,271 @@
+/*
+ * tpm_ioctl.h
+ *
+ * (c) Copyright IBM Corporation 2014, 2015.
+ *
+ * This file is licensed under the terms of the 3-clause BSD license
+ */
+
+#ifndef TPM_IOCTL_H
+#define TPM_IOCTL_H
+
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+
+/*
+ * Every response from a command involving a TPM command execution must hold
+ * the ptm_res as the first element.
+ * ptm_res corresponds to the error code of a command executed by the TPM.
+ */
+
+typedef uint32_t ptm_res;
+
+/* PTM_GET_TPMESTABLISHED: get the establishment bit */
+struct ptm_est {
+    union {
+        struct {
+            ptm_res tpm_result;
+            unsigned char bit; /* TPM established bit */
+        } resp; /* response */
+    } u;
+};
+
+/* PTM_RESET_TPMESTABLISHED: reset establishment bit */
+struct ptm_reset_est {
+    union {
+        struct {
+            uint8_t loc; /* locality to use */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/* PTM_INIT */
+struct ptm_init {
+    union {
+        struct {
+            uint32_t init_flags; /* see definitions below */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/* above init_flags */
+#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)
+    /* delete volatile state file after reading it */
+
+/* PTM_SET_LOCALITY */
+struct ptm_loc {
+    union {
+        struct {
+            uint8_t loc; /* locality to set */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/* PTM_HASH_DATA: hash given data */
+struct ptm_hdata {
+    union {
+        struct {
+            uint32_t length;
+            uint8_t data[4096];
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/*
+ * size of the TPM state blob to transfer; x86_64 can handle 8k,
+ * ppc64le only ~7k; keep the response below a 4k page size
+ */
+#define PTM_STATE_BLOB_SIZE (3 * 1024)
+
+/*
+ * The following is the data structure to get state blobs from the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple 
reads
+ * with this ioctl and with adjusted offset are necessary. All bytes
+ * must be transferred and the transfer is done once the last byte has been
+ * returned.
+ * It is possible to use the read() interface for reading the data; however, 
the
+ * first bytes of the state blob will be part of the response to the ioctl(); a
+ * subsequent read() is only necessary if the total length (totlength) exceeds
+ * the number of received bytes. seek() is not supported.
+ */
+struct ptm_getstate {
+    union {
+        struct {
+            uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */
+            uint32_t type;        /* which blob to pull */
+            uint32_t offset;      /* offset from where to read */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+            uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */
+            uint32_t totlength;   /* total length that will be transferred */
+            uint32_t length;      /* number of bytes in following buffer */
+            uint8_t  data[PTM_STATE_BLOB_SIZE];
+        } resp; /* response */
+    } u;
+};
+
+/* TPM state blob types */
+#define PTM_BLOB_TYPE_PERMANENT  1
+#define PTM_BLOB_TYPE_VOLATILE   2
+#define PTM_BLOB_TYPE_SAVESTATE  3
+
+/* state_flags above : */
+#define PTM_STATE_FLAG_DECRYPTED     1 /* on input:  get decrypted state */
+#define PTM_STATE_FLAG_ENCRYPTED     2 /* on output: state is encrypted */
+
+/*
+ * The following is the data structure to set state blobs in the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple
+ * 'writes' using this ioctl are necessary. The last packet is indicated
+ * by the length being smaller than the PTM_STATE_BLOB_SIZE.
+ * The very first packet may have a length indicator of '0' enabling
+ * a write() with all the bytes from a buffer. If the write() interface
+ * is used, a final ioctl with a non-full buffer must be made to indicate
+ * that all data were transferred (a write with 0 bytes would not work).
+ */
+struct ptm_setstate {
+    union {
+        struct {
+            uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */
+            uint32_t type;        /* which blob to set */
+            uint32_t length;      /* length of the data;
+                                     use 0 on the first packet to
+                                     transfer using write() */
+            uint8_t data[PTM_STATE_BLOB_SIZE];
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+        } resp; /* response */
+    } u;
+};
+
+/*
+ * PTM_GET_CONFIG: Data structure to get runtime configuration information
+ * such as which keys are applied.
+ */
+struct ptm_getconfig {
+    union {
+        struct {
+            ptm_res tpm_result;
+            uint32_t flags;
+        } resp; /* response */
+    } u;
+};
+
+#define PTM_CONFIG_FLAG_FILE_KEY        0x1
+#define PTM_CONFIG_FLAG_MIGRATION_KEY   0x2
+
+/*
+ * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the TPM.
+ * A 0 on input queries for the current buffer size. Any other
+ * number will try to set the buffer size. The returned number is
+ * the buffer size that will be used, which can be larger than the
+ * requested one, if it was below the minimum, or smaller than the
+ * requested one, if it was above the maximum.
+ */
+struct ptm_setbuffersize {
+    union {
+        struct {
+            uint32_t buffersize; /* 0 to query for current buffer size */
+        } req; /* request */
+        struct {
+            ptm_res tpm_result;
+            uint32_t buffersize; /* buffer size in use */
+            uint32_t minsize; /* min. supported buffer size */
+            uint32_t maxsize; /* max. supported buffer size */
+        } resp; /* response */
+    } u;
+};
+
+
+typedef uint64_t ptm_cap;
+typedef struct ptm_est ptm_est;
+typedef struct ptm_reset_est ptm_reset_est;
+typedef struct ptm_loc ptm_loc;
+typedef struct ptm_hdata ptm_hdata;
+typedef struct ptm_init ptm_init;
+typedef struct ptm_getstate ptm_getstate;
+typedef struct ptm_setstate ptm_setstate;
+typedef struct ptm_getconfig ptm_getconfig;
+typedef struct ptm_setbuffersize ptm_setbuffersize;
+
+/* capability flags returned by PTM_GET_CAPABILITY */
+#define PTM_CAP_INIT               (1)
+#define PTM_CAP_SHUTDOWN           (1 << 1)
+#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)
+#define PTM_CAP_SET_LOCALITY       (1 << 3)
+#define PTM_CAP_HASHING            (1 << 4)
+#define PTM_CAP_CANCEL_TPM_CMD     (1 << 5)
+#define PTM_CAP_STORE_VOLATILE     (1 << 6)
+#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)
+#define PTM_CAP_GET_STATEBLOB      (1 << 8)
+#define PTM_CAP_SET_STATEBLOB      (1 << 9)
+#define PTM_CAP_STOP               (1 << 10)
+#define PTM_CAP_GET_CONFIG         (1 << 11)
+#define PTM_CAP_SET_DATAFD         (1 << 12)
+#define PTM_CAP_SET_BUFFERSIZE     (1 << 13)
+
+enum {
+    PTM_GET_CAPABILITY     = _IOR('P', 0, ptm_cap),
+    PTM_INIT               = _IOWR('P', 1, ptm_init),
+    PTM_SHUTDOWN           = _IOR('P', 2, ptm_res),
+    PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),
+    PTM_SET_LOCALITY       = _IOWR('P', 4, ptm_loc),
+    PTM_HASH_START         = _IOR('P', 5, ptm_res),
+    PTM_HASH_DATA          = _IOWR('P', 6, ptm_hdata),
+    PTM_HASH_END           = _IOR('P', 7, ptm_res),
+    PTM_CANCEL_TPM_CMD     = _IOR('P', 8, ptm_res),
+    PTM_STORE_VOLATILE     = _IOR('P', 9, ptm_res),
+    PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),
+    PTM_GET_STATEBLOB      = _IOWR('P', 11, ptm_getstate),
+    PTM_SET_STATEBLOB      = _IOWR('P', 12, ptm_setstate),
+    PTM_STOP               = _IOR('P', 13, ptm_res),
+    PTM_GET_CONFIG         = _IOR('P', 14, ptm_getconfig),
+    PTM_SET_DATAFD         = _IOR('P', 15, ptm_res),
+    PTM_SET_BUFFERSIZE     = _IOWR('P', 16, ptm_setbuffersize),
+};
+
+/*
+ * Commands used by the non-CUSE TPMs
+ *
+ * All messages container big-endian data.
+ *
+ * The return messages only contain the 'resp' part of the unions
+ * in the data structures above. Besides that the limits in the
+ * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data
+ * and ptm_set_state:u.req.data) are 0xffffffff.
+ */
+enum {
+    CMD_GET_CAPABILITY = 1,
+    CMD_INIT,
+    CMD_SHUTDOWN,
+    CMD_GET_TPMESTABLISHED,
+    CMD_SET_LOCALITY,
+    CMD_HASH_START,
+    CMD_HASH_DATA,
+    CMD_HASH_END,
+    CMD_CANCEL_TPM_CMD,
+    CMD_STORE_VOLATILE,
+    CMD_RESET_TPMESTABLISHED,
+    CMD_GET_STATEBLOB,
+    CMD_SET_STATEBLOB,
+    CMD_STOP,
+    CMD_GET_CONFIG,
+    CMD_SET_DATAFD,
+    CMD_SET_BUFFERSIZE,
+};
+
+#endif /* TPM_IOCTL_H */
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
new file mode 100644
index 0000000000..7403807ec4
--- /dev/null
+++ b/backends/tpm/tpm_passthrough.c
@@ -0,0 +1,405 @@
+/*
+ *  passthrough TPM driver
+ *
+ *  Copyright (c) 2010 - 2013 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@xxxxxxxxxx>
+ *
+ *  Copyright (C) 2011 IAIK, Graz University of Technology
+ *    Author: Andreas Niederl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "qemu/sockets.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+#include "tpm_int.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+#include "trace.h"
+
+#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
+#define TPM_PASSTHROUGH(obj) \
+    OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
+
+/* data structures */
+struct TPMPassthruState {
+    TPMBackend parent;
+
+    TPMPassthroughOptions *options;
+    const char *tpm_dev;
+    int tpm_fd;
+    bool tpm_executing;
+    bool tpm_op_canceled;
+    int cancel_fd;
+
+    TPMVersion tpm_version;
+    size_t tpm_buffersize;
+};
+
+typedef struct TPMPassthruState TPMPassthruState;
+
+#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
+
+/* functions */
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
+
+static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
+{
+    int ret;
+ reread:
+    ret = read(fd, buf, len);
+    if (ret < 0) {
+        if (errno != EINTR && errno != EAGAIN) {
+            return -1;
+        }
+        goto reread;
+    }
+    return ret;
+}
+
+static void tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
+                                         const uint8_t *in, uint32_t in_len,
+                                         uint8_t *out, uint32_t out_len,
+                                         bool *selftest_done, Error **errp)
+{
+    ssize_t ret;
+    bool is_selftest;
+
+    /* FIXME: protect shared variables or use other sync mechanism */
+    tpm_pt->tpm_op_canceled = false;
+    tpm_pt->tpm_executing = true;
+    *selftest_done = false;
+
+    is_selftest = tpm_util_is_selftest(in, in_len);
+
+    ret = qemu_write_full(tpm_pt->tpm_fd, in, in_len);
+    if (ret != in_len) {
+        if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
+            error_setg_errno(errp, errno, "tpm_passthrough: error while "
+                             "transmitting data to TPM");
+        }
+        goto err_exit;
+    }
+
+    tpm_pt->tpm_executing = false;
+
+    ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
+    if (ret < 0) {
+        if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
+            error_setg_errno(errp, errno, "tpm_passthrough: error while "
+                             "reading data from TPM");
+        }
+    } else if (ret < sizeof(struct tpm_resp_hdr) ||
+               tpm_cmd_get_size(out) != ret) {
+        ret = -1;
+        error_setg_errno(errp, errno, "tpm_passthrough: received invalid "
+                     "response packet from TPM");
+    }
+
+    if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
+        *selftest_done = tpm_cmd_get_errcode(out) == 0;
+    }
+
+err_exit:
+    if (ret < 0) {
+        tpm_util_write_fatal_error_response(out, out_len);
+    }
+
+    tpm_pt->tpm_executing = false;
+}
+
+static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
+                                           Error **errp)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+    trace_tpm_passthrough_handle_request(cmd);
+
+    tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len,
+                                 cmd->out, cmd->out_len, &cmd->selftest_done,
+                                 errp);
+}
+
+static void tpm_passthrough_reset(TPMBackend *tb)
+{
+    trace_tpm_passthrough_reset();
+
+    tpm_passthrough_cancel_cmd(tb);
+}
+
+static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
+{
+    return false;
+}
+
+static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
+                                                      uint8_t locty)
+{
+    /* only a TPM 2.0 will support this */
+    return 0;
+}
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+    int n;
+
+    /*
+     * As of Linux 3.7 the tpm_tis driver does not properly cancel
+     * commands on all TPM manufacturers' TPMs.
+     * Only cancel if we're busy so we don't cancel someone else's
+     * command, e.g., a command executed on the host.
+     */
+    if (tpm_pt->tpm_executing) {
+        if (tpm_pt->cancel_fd >= 0) {
+            tpm_pt->tpm_op_canceled = true;
+            n = write(tpm_pt->cancel_fd, "-", 1);
+            if (n != 1) {
+                error_report("Canceling TPM command failed: %s",
+                             strerror(errno));
+            }
+        } else {
+            error_report("Cannot cancel TPM command due to missing "
+                         "TPM sysfs cancel entry");
+        }
+    }
+}
+
+static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+    return tpm_pt->tpm_version;
+}
+
+static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+    int ret;
+
+    ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version,
+                                   &tpm_pt->tpm_buffersize);
+    if (ret < 0) {
+        tpm_pt->tpm_buffersize = 4096;
+    }
+    return tpm_pt->tpm_buffersize;
+}
+
+/*
+ * Unless path or file descriptor set has been provided by user,
+ * determine the sysfs cancel file following kernel documentation
+ * in Documentation/ABI/stable/sysfs-class-tpm.
+ * From /dev/tpm0 create /sys/class/tpm/tpm0/device/cancel
+ * before 4.0: /sys/class/misc/tpm0/device/cancel
+ */
+static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
+{
+    int fd = -1;
+    char *dev;
+    char path[PATH_MAX];
+
+    if (tpm_pt->options->cancel_path) {
+        fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY);
+        if (fd < 0) {
+            error_report("tpm_passthrough: Could not open TPM cancel path: %s",
+                         strerror(errno));
+        }
+        return fd;
+    }
+
+    dev = strrchr(tpm_pt->tpm_dev, '/');
+    if (!dev) {
+        error_report("tpm_passthrough: Bad TPM device path %s",
+                     tpm_pt->tpm_dev);
+        return -1;
+    }
+
+    dev++;
+    if (snprintf(path, sizeof(path), "/sys/class/tpm/%s/device/cancel",
+                 dev) < sizeof(path)) {
+        fd = qemu_open(path, O_WRONLY);
+        if (fd < 0) {
+            if (snprintf(path, sizeof(path), 
"/sys/class/misc/%s/device/cancel",
+                         dev) < sizeof(path)) {
+                fd = qemu_open(path, O_WRONLY);
+            }
+        }
+    }
+
+    if (fd < 0) {
+        error_report("tpm_passthrough: Could not guess TPM cancel path");
+    } else {
+        tpm_pt->options->cancel_path = g_strdup(path);
+    }
+
+    return fd;
+}
+
+static int
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+{
+    const char *value;
+
+    value = qemu_opt_get(opts, "cancel-path");
+    if (value) {
+        tpm_pt->options->cancel_path = g_strdup(value);
+        tpm_pt->options->has_cancel_path = true;
+    }
+
+    value = qemu_opt_get(opts, "path");
+    if (value) {
+        tpm_pt->options->has_path = true;
+        tpm_pt->options->path = g_strdup(value);
+    }
+
+    tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+    tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
+    if (tpm_pt->tpm_fd < 0) {
+        error_report("Cannot access TPM device using '%s': %s",
+                     tpm_pt->tpm_dev, strerror(errno));
+        return -1;
+    }
+
+    if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
+        error_report("'%s' is not a TPM device.",
+                     tpm_pt->tpm_dev);
+        return -1;
+    }
+
+    tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
+    if (tpm_pt->cancel_fd < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+{
+    Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
+
+    if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+        object_unref(obj);
+        return NULL;
+    }
+
+    return TPM_BACKEND(obj);
+}
+
+static int tpm_passthrough_startup_tpm(TPMBackend *tb, size_t buffersize)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+    if (buffersize && buffersize < tpm_pt->tpm_buffersize) {
+        error_report("Requested buffer size of %zu is smaller than host TPM's "
+                     "fixed buffer size of %zu",
+                     buffersize, tpm_pt->tpm_buffersize);
+        return -1;
+    }
+
+    return 0;
+}
+
+static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
+{
+    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
+
+    options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
+    options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
+                                             TPM_PASSTHROUGH(tb)->options);
+
+    return options;
+}
+
+static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {
+        .name = "cancel-path",
+        .type = QEMU_OPT_STRING,
+        .help = "Sysfs file entry for canceling TPM commands",
+    },
+    {
+        .name = "path",
+        .type = QEMU_OPT_STRING,
+        .help = "Path to TPM device on the host",
+    },
+    { /* end of list */ },
+};
+
+static void tpm_passthrough_inst_init(Object *obj)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
+
+    tpm_pt->options = g_new0(TPMPassthroughOptions, 1);
+    tpm_pt->tpm_fd = -1;
+    tpm_pt->cancel_fd = -1;
+}
+
+static void tpm_passthrough_inst_finalize(Object *obj)
+{
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
+
+    tpm_passthrough_cancel_cmd(TPM_BACKEND(obj));
+
+    if (tpm_pt->tpm_fd >= 0) {
+        qemu_close(tpm_pt->tpm_fd);
+    }
+    if (tpm_pt->cancel_fd >= 0) {
+        qemu_close(tpm_pt->cancel_fd);
+    }
+    qapi_free_TPMPassthroughOptions(tpm_pt->options);
+}
+
+static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
+{
+    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+
+    tbc->type = TPM_TYPE_PASSTHROUGH;
+    tbc->opts = tpm_passthrough_cmdline_opts;
+    tbc->desc = "Passthrough TPM backend driver";
+    tbc->create = tpm_passthrough_create;
+    tbc->startup_tpm = tpm_passthrough_startup_tpm;
+    tbc->reset = tpm_passthrough_reset;
+    tbc->cancel_cmd = tpm_passthrough_cancel_cmd;
+    tbc->get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag;
+    tbc->reset_tpm_established_flag =
+        tpm_passthrough_reset_tpm_established_flag;
+    tbc->get_tpm_version = tpm_passthrough_get_tpm_version;
+    tbc->get_buffer_size = tpm_passthrough_get_buffer_size;
+    tbc->get_tpm_options = tpm_passthrough_get_tpm_options;
+    tbc->handle_request = tpm_passthrough_handle_request;
+}
+
+static const TypeInfo tpm_passthrough_info = {
+    .name = TYPE_TPM_PASSTHROUGH,
+    .parent = TYPE_TPM_BACKEND,
+    .instance_size = sizeof(TPMPassthruState),
+    .class_init = tpm_passthrough_class_init,
+    .instance_init = tpm_passthrough_inst_init,
+    .instance_finalize = tpm_passthrough_inst_finalize,
+};
+
+static void tpm_passthrough_register(void)
+{
+    type_register_static(&tpm_passthrough_info);
+}
+
+type_init(tpm_passthrough_register)
diff --git a/backends/tpm/tpm_util.c b/backends/tpm/tpm_util.c
new file mode 100644
index 0000000000..cfc7572a61
--- /dev/null
+++ b/backends/tpm/tpm_util.c
@@ -0,0 +1,380 @@
+/*
+ * TPM utility functions
+ *
+ *  Copyright (c) 2010 - 2015 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@xxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "tpm_int.h"
+#include "exec/memory.h"
+#include "hw/qdev-properties.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+#include "trace.h"
+
+/* tpm backend property */
+
+static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
+                    Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    TPMBackend **be = qdev_get_prop_ptr(dev, opaque);
+    char *p;
+
+    p = g_strdup(*be ? (*be)->id : "");
+    visit_type_str(v, name, &p, errp);
+    g_free(p);
+}
+
+static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
+                    Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Error *local_err = NULL;
+    Property *prop = opaque;
+    TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
+    char *str;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_str(v, name, &str, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    s = qemu_find_tpm_be(str);
+    if (s == NULL) {
+        error_setg(errp, "Property '%s.%s' can't find value '%s'",
+                   object_get_typename(obj), prop->name, str);
+    } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) {
+        *be = s; /* weak reference, avoid cyclic ref */
+    }
+    g_free(str);
+}
+
+static void release_tpm(Object *obj, const char *name, void *opaque)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    TPMBackend **be = qdev_get_prop_ptr(dev, prop);
+
+    if (*be) {
+        tpm_backend_reset(*be);
+    }
+}
+
+const PropertyInfo qdev_prop_tpm = {
+    .name  = "str",
+    .description = "ID of a tpm to use as a backend",
+    .get   = get_tpm,
+    .set   = set_tpm,
+    .release = release_tpm,
+};
+
+/*
+ * Write an error message in the given output buffer.
+ */
+void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len)
+{
+    if (out_len >= sizeof(struct tpm_resp_hdr)) {
+        tpm_cmd_set_tag(out, TPM_TAG_RSP_COMMAND);
+        tpm_cmd_set_size(out, sizeof(struct tpm_resp_hdr));
+        tpm_cmd_set_error(out, TPM_FAIL);
+    }
+}
+
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
+{
+    if (in_len >= sizeof(struct tpm_req_hdr)) {
+        return tpm_cmd_get_ordinal(in) == TPM_ORD_ContinueSelfTest;
+    }
+
+    return false;
+}
+
+/*
+ * Send request to a TPM device. We expect a response within one second.
+ */
+static int tpm_util_request(int fd,
+                            const void *request,
+                            size_t requestlen,
+                            void *response,
+                            size_t responselen)
+{
+    fd_set readfds;
+    int n;
+    struct timeval tv = {
+        .tv_sec = 1,
+        .tv_usec = 0,
+    };
+
+    n = write(fd, request, requestlen);
+    if (n < 0) {
+        return -errno;
+    }
+    if (n != requestlen) {
+        return -EFAULT;
+    }
+
+    FD_ZERO(&readfds);
+    FD_SET(fd, &readfds);
+
+    /* wait for a second */
+    n = select(fd + 1, &readfds, NULL, NULL, &tv);
+    if (n != 1) {
+        return -errno;
+    }
+
+    n = read(fd, response, responselen);
+    if (n < sizeof(struct tpm_resp_hdr)) {
+        return -EFAULT;
+    }
+
+    /* check the header */
+    if (tpm_cmd_get_size(response) != n) {
+        return -EMSGSIZE;
+    }
+
+    return 0;
+}
+
+/*
+ * A basic test of a TPM device. We expect a well formatted response header
+ * (error response is fine).
+ */
+static int tpm_util_test(int fd,
+                         const void *request,
+                         size_t requestlen,
+                         uint16_t *return_tag)
+{
+    char buf[1024];
+    ssize_t ret;
+
+    ret = tpm_util_request(fd, request, requestlen,
+                           buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    *return_tag = tpm_cmd_get_tag(buf);
+
+    return 0;
+}
+
+/*
+ * Probe for the TPM device in the back
+ * Returns 0 on success with the version of the probed TPM set, 1 on failure.
+ */
+int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
+{
+    /*
+     * Sending a TPM1.2 command to a TPM2 should return a TPM1.2
+     * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e)
+     *
+     * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the
+     * header.
+     * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag
+     * in the header and an error code.
+     */
+    const struct tpm_req_hdr test_req = {
+        .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
+        .len = cpu_to_be32(sizeof(test_req)),
+        .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
+    };
+
+    const struct tpm_req_hdr test_req_tpm2 = {
+        .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+        .len = cpu_to_be32(sizeof(test_req_tpm2)),



 


Rackspace

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