summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs1
-rw-r--r--backends/baum.c4
-rw-r--r--backends/msmouse.c4
-rwxr-xr-xconfigure28
-rw-r--r--cpu-exec.c70
-rw-r--r--cpus.c17
-rw-r--r--default-configs/i386-softmmu.mak2
-rw-r--r--default-configs/x86_64-softmmu.mak2
-rw-r--r--exec.c43
-rw-r--r--gdbstub.c2
-rw-r--r--hmp-commands.hx65
-rw-r--r--hmp.c44
-rw-r--r--hmp.h1
-rw-r--r--hw/alpha_typhoon.c18
-rw-r--r--hw/apic.c25
-rw-r--r--hw/arm/omap1.c11
-rw-r--r--hw/arm/pic_cpu.c20
-rw-r--r--hw/arm/pxa2xx.c7
-rw-r--r--hw/arm/pxa2xx_gpio.c5
-rw-r--r--hw/arm/pxa2xx_pic.c13
-rw-r--r--hw/cris/pic_cpu.c14
-rw-r--r--hw/i386/pc.c14
-rw-r--r--hw/i386/pc_piix.c3
-rw-r--r--hw/i386/xen_machine_pv.c6
-rw-r--r--hw/lm32/lm32_boards.c9
-rw-r--r--hw/lm32/milkymist.c9
-rw-r--r--hw/lpc_ich9.c2
-rw-r--r--hw/microblaze/pic_cpu.c15
-rw-r--r--hw/mips/mips_int.c10
-rw-r--r--hw/openrisc/cputimer.c4
-rw-r--r--hw/openrisc/pic_cpu.c5
-rw-r--r--hw/ppc/e500.c10
-rw-r--r--hw/ppc/ppc.c34
-rw-r--r--hw/ppc/ppc405_uc.c4
-rw-r--r--hw/ppc/ppce500_spin.c2
-rw-r--r--hw/ppc/spapr.c10
-rw-r--r--hw/ppc/spapr_hcall.c2
-rw-r--r--hw/ppc/spapr_rtas.c6
-rw-r--r--hw/s390x/s390-virtio.c14
-rw-r--r--hw/sh4/sh7750.c10
-rw-r--r--hw/sh_intc.c14
-rw-r--r--hw/sparc/leon3.c12
-rw-r--r--hw/sparc/sun4m.c35
-rw-r--r--hw/sparc64/sun4u.c26
-rw-r--r--hw/unicore32/puv3.c10
-rw-r--r--hw/xtensa/pic_cpu.c12
-rw-r--r--include/char/char.h8
-rw-r--r--include/exec/cpu-all.h15
-rw-r--r--include/exec/cpu-defs.h2
-rw-r--r--include/migration/vmstate.h16
-rw-r--r--include/qemu/sockets.h2
-rw-r--r--include/qom/cpu.h63
-rw-r--r--include/tpm/tpm.h21
-rw-r--r--include/ui/console.h4
-rw-r--r--include/ui/qemu-spice.h7
-rw-r--r--kvm-all.c6
-rw-r--r--linux-user/main.c24
-rw-r--r--linux-user/socket.h69
-rw-r--r--linux-user/sparc/syscall_nr.h2
-rw-r--r--linux-user/strace.c103
-rw-r--r--linux-user/syscall.c134
-rw-r--r--monitor.c21
-rw-r--r--qapi-schema.json208
-rw-r--r--qemu-char.c405
-rw-r--r--qemu-options.hx74
-rw-r--r--qga/channel-win32.c2
-rw-r--r--qga/commands-posix.c268
-rw-r--r--qga/commands-win32.c23
-rw-r--r--qga/guest-agent-core.h1
-rw-r--r--qga/main.c185
-rw-r--r--qga/qapi-schema.json111
-rw-r--r--qga/service-win32.c2
-rw-r--r--qmp-commands.hx18
-rw-r--r--qom/cpu.c7
-rw-r--r--savevm.c7
-rw-r--r--spice-qemu-char.c88
-rw-r--r--stubs/vmstate.c2
-rw-r--r--target-alpha/cpu-qom.h2
-rw-r--r--target-alpha/cpu.c1
-rw-r--r--target-alpha/cpu.h5
-rw-r--r--target-alpha/helper.c4
-rw-r--r--target-alpha/translate.c3
-rw-r--r--target-arm/cpu-qom.h3
-rw-r--r--target-arm/cpu.c15
-rw-r--r--target-arm/cpu.h5
-rw-r--r--target-arm/helper.c23
-rw-r--r--target-arm/op_helper.c4
-rw-r--r--target-cris/cpu-qom.h2
-rw-r--r--target-cris/cpu.c1
-rw-r--r--target-cris/cpu.h5
-rw-r--r--target-cris/helper.c402
-rw-r--r--target-cris/translate.c3
-rw-r--r--target-i386/cpu-qom.h10
-rw-r--r--target-i386/cpu.c5
-rw-r--r--target-i386/cpu.h25
-rw-r--r--target-i386/helper.c18
-rw-r--r--target-i386/kvm.c50
-rw-r--r--target-i386/machine.c215
-rw-r--r--target-i386/misc_helper.c21
-rw-r--r--target-i386/seg_helper.c5
-rw-r--r--target-i386/svm_helper.c9
-rw-r--r--target-lm32/cpu-qom.h6
-rw-r--r--target-lm32/cpu.c3
-rw-r--r--target-lm32/cpu.h7
-rw-r--r--target-lm32/helper.c5
-rw-r--r--target-lm32/machine.c25
-rw-r--r--target-lm32/op_helper.c4
-rw-r--r--target-m68k/cpu-qom.h2
-rw-r--r--target-m68k/cpu.c1
-rw-r--r--target-m68k/cpu.h5
-rw-r--r--target-m68k/helper.c10
-rw-r--r--target-m68k/op_helper.c14
-rw-r--r--target-m68k/qregs.def1
-rw-r--r--target-m68k/translate.c8
-rw-r--r--target-microblaze/cpu-qom.h2
-rw-r--r--target-microblaze/cpu.c1
-rw-r--r--target-microblaze/cpu.h5
-rw-r--r--target-microblaze/helper.c9
-rw-r--r--target-mips/cpu-qom.h2
-rw-r--r--target-mips/cpu.c2
-rw-r--r--target-mips/cpu.h5
-rw-r--r--target-mips/helper.c5
-rw-r--r--target-mips/op_helper.c23
-rw-r--r--target-mips/translate.c4
-rw-r--r--target-openrisc/cpu.c1
-rw-r--r--target-openrisc/cpu.h6
-rw-r--r--target-openrisc/interrupt.c4
-rw-r--r--target-openrisc/interrupt_helper.c3
-rw-r--r--target-openrisc/sys_helper.c3
-rw-r--r--target-ppc/cpu-qom.h2
-rw-r--r--target-ppc/cpu.h6
-rw-r--r--target-ppc/excp_helper.c34
-rw-r--r--target-ppc/helper_regs.h11
-rw-r--r--target-ppc/kvm.c16
-rw-r--r--target-ppc/translate.c3
-rw-r--r--target-ppc/translate_init.c1
-rw-r--r--target-s390x/cpu-qom.h2
-rw-r--r--target-s390x/cpu.c9
-rw-r--r--target-s390x/cpu.h12
-rw-r--r--target-s390x/helper.c19
-rw-r--r--target-sh4/cpu-qom.h15
-rw-r--r--target-sh4/cpu.c181
-rw-r--r--target-sh4/cpu.h8
-rw-r--r--target-sh4/helper.c13
-rw-r--r--target-sh4/op_helper.c4
-rw-r--r--target-sh4/translate.c84
-rw-r--r--target-sparc/cpu-qom.h2
-rw-r--r--target-sparc/cpu.c2
-rw-r--r--target-sparc/cpu.h6
-rw-r--r--target-sparc/helper.c4
-rw-r--r--target-sparc/int32_helper.c4
-rw-r--r--target-sparc/int64_helper.c4
-rw-r--r--target-unicore32/cpu-qom.h2
-rw-r--r--target-unicore32/cpu.c1
-rw-r--r--target-unicore32/cpu.h5
-rw-r--r--target-unicore32/helper.c5
-rw-r--r--target-unicore32/softmmu.c6
-rw-r--r--target-xtensa/cpu-qom.h2
-rw-r--r--target-xtensa/cpu.c1
-rw-r--r--target-xtensa/cpu.h1
-rw-r--r--target-xtensa/helper.c5
-rw-r--r--target-xtensa/op_helper.c5
-rw-r--r--tpm/Makefile.objs6
-rw-r--r--tpm/tpm.c357
-rw-r--r--tpm/tpm_backend.c58
-rw-r--r--tpm/tpm_backend.h45
-rw-r--r--tpm/tpm_int.h116
-rw-r--r--tpm/tpm_passthrough.c530
-rw-r--r--tpm/tpm_tis.c929
-rw-r--r--tpm/tpm_tis.h80
-rw-r--r--trace-events1
-rw-r--r--translate-all.c18
-rw-r--r--ui/console.c61
-rw-r--r--ui/gtk.c2
-rw-r--r--util/qemu-sockets.c25
-rw-r--r--vl.c78
-rw-r--r--xen-all.c10
177 files changed, 5188 insertions, 1177 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 8c90b92d01..f99841ce54 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -74,6 +74,7 @@ common-obj-y += bt-host.o bt-vhci.o
 
 common-obj-y += dma-helpers.o
 common-obj-y += vl.o
+common-obj-y += tpm/
 
 common-obj-$(CONFIG_SLIRP) += slirp/
 
diff --git a/backends/baum.c b/backends/baum.c
index 9063aea2cf..d7d658c224 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -561,7 +561,7 @@ static void baum_close(struct CharDriverState *chr)
     g_free(baum);
 }
 
-static CharDriverState *chr_baum_init(QemuOpts *opts)
+CharDriverState *chr_baum_init(void)
 {
     BaumDriverState *baum;
     CharDriverState *chr;
@@ -627,7 +627,7 @@ fail_handle:
 
 static void register_types(void)
 {
-    register_char_driver("braille", chr_baum_init);
+    register_char_driver_qapi("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL);
 }
 
 type_init(register_types);
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 407ec87784..61052fe783 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -63,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr)
     g_free (chr);
 }
 
-static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
+CharDriverState *qemu_chr_open_msmouse(void)
 {
     CharDriverState *chr;
 
@@ -78,7 +78,7 @@ static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
 
 static void register_types(void)
 {
-    register_char_driver("msmouse", qemu_chr_open_msmouse);
+    register_char_driver_qapi("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL);
 }
 
 type_init(register_types);
diff --git a/configure b/configure
index 84317c6826..46a75947cd 100755
--- a/configure
+++ b/configure
@@ -228,6 +228,7 @@ glusterfs=""
 virtio_blk_data_plane=""
 gtk=""
 gtkabi="2.0"
+tpm="no"
 
 # parse CC options first
 for opt do
@@ -905,6 +906,8 @@ for opt do
   ;;
   --with-gtkabi=*) gtkabi="$optarg"
   ;;
+  --enable-tpm) tpm="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -1160,6 +1163,7 @@ echo "  --enable-glusterfs       enable GlusterFS backend"
 echo "  --disable-glusterfs      disable GlusterFS backend"
 echo "  --enable-gcov            enable test coverage analysis with gcov"
 echo "  --gcov=GCOV              use specified gcov [$gcov_tool]"
+echo "  --enable-tpm             enable TPM support"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -2760,6 +2764,20 @@ if compile_prog "" "" ; then
   epoll_pwait=yes
 fi
 
+# check for sendfile support
+sendfile=no
+cat > $TMPC << EOF
+#include <sys/sendfile.h>
+
+int main(void)
+{
+    return sendfile(0, 0, 0, 0);
+}
+EOF
+if compile_prog "" "" ; then
+  sendfile=yes
+fi
+
 # Check if tools are available to build documentation.
 if test "$docs" != "no" ; then
   if has makeinfo && has pod2man; then
@@ -3420,6 +3438,7 @@ echo "GlusterFS support $glusterfs"
 echo "virtio-blk-data-plane $virtio_blk_data_plane"
 echo "gcov              $gcov_tool"
 echo "gcov enabled      $gcov"
+echo "TPM support       $tpm"
 
 if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -3628,6 +3647,9 @@ fi
 if test "$epoll_pwait" = "yes" ; then
   echo "CONFIG_EPOLL_PWAIT=y" >> $config_host_mak
 fi
+if test "$sendfile" = "yes" ; then
+  echo "CONFIG_SENDFILE=y" >> $config_host_mak
+fi
 if test "$inotify" = "yes" ; then
   echo "CONFIG_INOTIFY=y" >> $config_host_mak
 fi
@@ -4329,6 +4351,12 @@ if test "$gprof" = "yes" ; then
   fi
 fi
 
+if test "$tpm" = "yes"; then
+  if test "$target_softmmu" = "yes" ; then
+    echo "CONFIG_TPM=y" >> $config_host_mak
+  fi
+fi
+
 if test "$ARCH" = "tci"; then
   linker_script=""
 else
diff --git a/cpu-exec.c b/cpu-exec.c
index 9092145d0b..94fedc5805 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -198,17 +198,21 @@ volatile sig_atomic_t exit_request;
 int cpu_exec(CPUArchState *env)
 {
     CPUState *cpu = ENV_GET_CPU(env);
+#if !(defined(CONFIG_USER_ONLY) && \
+      (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+#endif
     int ret, interrupt_request;
     TranslationBlock *tb;
     uint8_t *tc_ptr;
     tcg_target_ulong next_tb;
 
-    if (env->halted) {
+    if (cpu->halted) {
         if (!cpu_has_work(cpu)) {
             return EXCP_HALTED;
         }
 
-        env->halted = 0;
+        cpu->halted = 0;
     }
 
     cpu_single_env = env;
@@ -265,12 +269,12 @@ int cpu_exec(CPUArchState *env)
                        which will be handled outside the cpu execution
                        loop */
 #if defined(TARGET_I386)
-                    do_interrupt(env);
+                    cc->do_interrupt(cpu);
 #endif
                     ret = env->exception_index;
                     break;
 #else
-                    do_interrupt(env);
+                    cc->do_interrupt(cpu);
                     env->exception_index = -1;
 #endif
                 }
@@ -278,14 +282,14 @@ int cpu_exec(CPUArchState *env)
 
             next_tb = 0; /* force lookup of first TB */
             for(;;) {
-                interrupt_request = env->interrupt_request;
+                interrupt_request = cpu->interrupt_request;
                 if (unlikely(interrupt_request)) {
                     if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
                         /* Mask out external interrupts for this step. */
                         interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
                     }
                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
-                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
+                        cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                         env->exception_index = EXCP_DEBUG;
                         cpu_loop_exit(env);
                     }
@@ -293,8 +297,8 @@ int cpu_exec(CPUArchState *env)
     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
     defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
                     if (interrupt_request & CPU_INTERRUPT_HALT) {
-                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
-                        env->halted = 1;
+                        cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
+                        cpu->halted = 1;
                         env->exception_index = EXCP_HLT;
                         cpu_loop_exit(env);
                     }
@@ -302,7 +306,7 @@ int cpu_exec(CPUArchState *env)
 #if defined(TARGET_I386)
 #if !defined(CONFIG_USER_ONLY)
                     if (interrupt_request & CPU_INTERRUPT_POLL) {
-                        env->interrupt_request &= ~CPU_INTERRUPT_POLL;
+                        cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
                         apic_poll_irq(env->apic_state);
                     }
 #endif
@@ -319,17 +323,17 @@ int cpu_exec(CPUArchState *env)
                             !(env->hflags & HF_SMM_MASK)) {
                             cpu_svm_check_intercept_param(env, SVM_EXIT_SMI,
                                                           0);
-                            env->interrupt_request &= ~CPU_INTERRUPT_SMI;
+                            cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
                             do_smm_enter(env);
                             next_tb = 0;
                         } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
                                    !(env->hflags2 & HF2_NMI_MASK)) {
-                            env->interrupt_request &= ~CPU_INTERRUPT_NMI;
+                            cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
                             env->hflags2 |= HF2_NMI_MASK;
                             do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
                             next_tb = 0;
                         } else if (interrupt_request & CPU_INTERRUPT_MCE) {
-                            env->interrupt_request &= ~CPU_INTERRUPT_MCE;
+                            cpu->interrupt_request &= ~CPU_INTERRUPT_MCE;
                             do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
                             next_tb = 0;
                         } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
@@ -341,7 +345,8 @@ int cpu_exec(CPUArchState *env)
                             int intno;
                             cpu_svm_check_intercept_param(env, SVM_EXIT_INTR,
                                                           0);
-                            env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
+                            cpu->interrupt_request &= ~(CPU_INTERRUPT_HARD |
+                                                        CPU_INTERRUPT_VIRQ);
                             intno = cpu_get_pic_interrupt(env);
                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
                             do_interrupt_x86_hardirq(env, intno, 1);
@@ -359,7 +364,7 @@ int cpu_exec(CPUArchState *env)
                             intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
                             do_interrupt_x86_hardirq(env, intno, 1);
-                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+                            cpu->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
                             next_tb = 0;
 #endif
                         }
@@ -370,15 +375,16 @@ int cpu_exec(CPUArchState *env)
                     }
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
                         ppc_hw_interrupt(env);
-                        if (env->pending_interrupts == 0)
-                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+                        if (env->pending_interrupts == 0) {
+                            cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
+                        }
                         next_tb = 0;
                     }
 #elif defined(TARGET_LM32)
                     if ((interrupt_request & CPU_INTERRUPT_HARD)
                         && (env->ie & IE_IE)) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_MICROBLAZE)
@@ -387,7 +393,7 @@ int cpu_exec(CPUArchState *env)
                         && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
                         && !(env->iflags & (D_FLAG | IMM_FLAG))) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_MIPS)
@@ -396,7 +402,7 @@ int cpu_exec(CPUArchState *env)
                         /* Raise it */
                         env->exception_index = EXCP_EXT_INTERRUPT;
                         env->error_code = 0;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_OPENRISC)
@@ -412,7 +418,7 @@ int cpu_exec(CPUArchState *env)
                         }
                         if (idx >= 0) {
                             env->exception_index = idx;
-                            do_interrupt(env);
+                            cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
                     }
@@ -427,7 +433,7 @@ int cpu_exec(CPUArchState *env)
                                   cpu_pil_allowed(env, pil)) ||
                                   type != TT_EXTINT) {
                                 env->exception_index = env->interrupt_index;
-                                do_interrupt(env);
+                                cc->do_interrupt(cpu);
                                 next_tb = 0;
                             }
                         }
@@ -436,7 +442,7 @@ int cpu_exec(CPUArchState *env)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
                         && !(env->uncached_cpsr & CPSR_F)) {
                         env->exception_index = EXCP_FIQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
                     /* ARMv7-M interrupt return works by loading a magic value
@@ -452,19 +458,19 @@ int cpu_exec(CPUArchState *env)
                         && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                             || !(env->uncached_cpsr & CPSR_I))) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_UNICORE32)
                     if (interrupt_request & CPU_INTERRUPT_HARD
                         && !(env->uncached_asr & ASR_I)) {
                         env->exception_index = UC32_EXCP_INTR;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_SH4)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_ALPHA)
@@ -495,7 +501,7 @@ int cpu_exec(CPUArchState *env)
                         if (idx >= 0) {
                             env->exception_index = idx;
                             env->error_code = 0;
-                            do_interrupt(env);
+                            cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
                     }
@@ -504,7 +510,7 @@ int cpu_exec(CPUArchState *env)
                         && (env->pregs[PR_CCS] & I_FLAG)
                         && !env->locked_irq) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
                     if (interrupt_request & CPU_INTERRUPT_NMI) {
@@ -516,7 +522,7 @@ int cpu_exec(CPUArchState *env)
                         }
                         if ((env->pregs[PR_CCS] & m_flag_archval)) {
                             env->exception_index = EXCP_NMI;
-                            do_interrupt(env);
+                            cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
                     }
@@ -536,20 +542,20 @@ int cpu_exec(CPUArchState *env)
 #elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                         (env->psw.mask & PSW_MASK_EXT)) {
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_XTENSA)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
                         env->exception_index = EXC_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #endif
                    /* Don't use the cached interrupt_request value,
                       do_interrupt may have updated the EXITTB flag. */
-                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
-                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
+                    if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) {
+                        cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                         /* ensure that no TB jump will be modified as
                            the program flow was changed */
                         next_tb = 0;
diff --git a/cpus.c b/cpus.c
index c4b021dd2e..e919dd7fb6 100644
--- a/cpus.c
+++ b/cpus.c
@@ -72,7 +72,7 @@ static bool cpu_thread_is_idle(CPUArchState *env)
     if (cpu->stopped || !runstate_is_running()) {
         return true;
     }
-    if (!env->halted || qemu_cpu_has_work(cpu) ||
+    if (!cpu->halted || qemu_cpu_has_work(cpu) ||
         kvm_async_interrupts_enabled()) {
         return false;
     }
@@ -1198,7 +1198,7 @@ CpuInfoList *qmp_query_cpus(Error **errp)
         info->value = g_malloc0(sizeof(*info->value));
         info->value->CPU = cpu->cpu_index;
         info->value->current = (env == first_cpu);
-        info->value->halted = env->halted;
+        info->value->halted = cpu->halted;
         info->value->thread_id = cpu->thread_id;
 #if defined(TARGET_I386)
         info->value->has_pc = true;
@@ -1241,18 +1241,13 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename,
         cpu_index = 0;
     }
 
-    for (env = first_cpu; env; env = env->next_cpu) {
-        cpu = ENV_GET_CPU(env);
-        if (cpu_index == cpu->cpu_index) {
-            break;
-        }
-    }
-
-    if (env == NULL) {
+    cpu = qemu_get_cpu(cpu_index);
+    if (cpu == NULL) {
         error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
                   "a CPU number");
         return;
     }
+    env = cpu->env_ptr;
 
     f = fopen(filename, "wb");
     if (!f) {
@@ -1314,7 +1309,7 @@ void qmp_inject_nmi(Error **errp)
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
         if (!env->apic_state) {
-            cpu_interrupt(env, CPU_INTERRUPT_NMI);
+            cpu_interrupt(CPU(x86_env_get_cpu(env)), CPU_INTERRUPT_NMI);
         } else {
             apic_deliver_nmi(env->apic_state);
         }
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 1b23025a98..df9e126c1f 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -26,3 +26,5 @@ CONFIG_HPET=y
 CONFIG_APPLESMC=y
 CONFIG_I8259=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_TPM_TIS=y
+CONFIG_TPM_PASSTHROUGH=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 3392f5abd6..ab3cd5fc35 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -26,3 +26,5 @@ CONFIG_HPET=y
 CONFIG_APPLESMC=y
 CONFIG_I8259=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_TPM_TIS=y
+CONFIG_TPM_PASSTHROUGH=y
diff --git a/exec.c b/exec.c
index 46a283071a..8a6aac36e3 100644
--- a/exec.c
+++ b/exec.c
@@ -219,16 +219,16 @@ void cpu_exec_init_all(void)
 #endif
 }
 
-#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
+#if !defined(CONFIG_USER_ONLY)
 
 static int cpu_common_post_load(void *opaque, int version_id)
 {
-    CPUArchState *env = opaque;
+    CPUState *cpu = opaque;
 
     /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
        version_id is increased. */
-    env->interrupt_request &= ~0x01;
-    tlb_flush(env, 1);
+    cpu->interrupt_request &= ~0x01;
+    tlb_flush(cpu->env_ptr, 1);
 
     return 0;
 }
@@ -240,11 +240,13 @@ static const VMStateDescription vmstate_cpu_common = {
     .minimum_version_id_old = 1,
     .post_load = cpu_common_post_load,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT32(halted, CPUArchState),
-        VMSTATE_UINT32(interrupt_request, CPUArchState),
+        VMSTATE_UINT32(halted, CPUState),
+        VMSTATE_UINT32(interrupt_request, CPUState),
         VMSTATE_END_OF_LIST()
     }
 };
+#else
+#define vmstate_cpu_common vmstate_dummy
 #endif
 
 CPUState *qemu_get_cpu(int index)
@@ -260,12 +262,13 @@ CPUState *qemu_get_cpu(int index)
         env = env->next_cpu;
     }
 
-    return cpu;
+    return env ? cpu : NULL;
 }
 
 void cpu_exec_init(CPUArchState *env)
 {
     CPUState *cpu = ENV_GET_CPU(env);
+    CPUClass *cc = CPU_GET_CLASS(cpu);
     CPUArchState **penv;
     int cpu_index;
 
@@ -290,11 +293,15 @@ void cpu_exec_init(CPUArchState *env)
 #if defined(CONFIG_USER_ONLY)
     cpu_list_unlock();
 #endif
+    vmstate_register(NULL, cpu_index, &vmstate_cpu_common, cpu);
 #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
-    vmstate_register(NULL, cpu_index, &vmstate_cpu_common, env);
     register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION,
                     cpu_save, cpu_load, env);
+    assert(cc->vmsd == NULL);
 #endif
+    if (cc->vmsd != NULL) {
+        vmstate_register(NULL, cpu_index, cc->vmsd, cpu);
+    }
 }
 
 #if defined(TARGET_HAS_ICE)
@@ -485,11 +492,6 @@ void cpu_single_step(CPUArchState *env, int enabled)
 #endif
 }
 
-void cpu_reset_interrupt(CPUArchState *env, int mask)
-{
-    env->interrupt_request &= ~mask;
-}
-
 void cpu_exit(CPUArchState *env)
 {
     CPUState *cpu = ENV_GET_CPU(env);
@@ -844,6 +846,8 @@ static void *file_ram_alloc(RAMBlock *block,
                             const char *path)
 {
     char *filename;
+    char *sanitized_name;
+    char *c;
     void *area;
     int fd;
 #ifdef MAP_POPULATE
@@ -865,7 +869,16 @@ static void *file_ram_alloc(RAMBlock *block,
         return NULL;
     }
 
-    filename = g_strdup_printf("%s/qemu_back_mem.XXXXXX", path);
+    /* Make name safe to use with mkstemp by replacing '/' with '_'. */
+    sanitized_name = g_strdup(block->mr->name);
+    for (c = sanitized_name; *c != '\0'; c++) {
+        if (*c == '/')
+            *c = '_';
+    }
+
+    filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
+                               sanitized_name);
+    g_free(sanitized_name);
 
     fd = mkstemp(filename);
     if (fd < 0) {
@@ -1465,7 +1478,7 @@ static void check_watchpoint(int offset, int len_mask, int flags)
         /* We re-entered the check after replacing the TB. Now raise
          * the debug interrupt so that is will trigger after the
          * current instruction. */
-        cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
+        cpu_interrupt(ENV_GET_CPU(env), CPU_INTERRUPT_DEBUG);
         return;
     }
     vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
diff --git a/gdbstub.c b/gdbstub.c
index e414ad9157..43b7d4d00f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2408,7 +2408,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
                 cpu_synchronize_state(env);
                 len = snprintf((char *)mem_buf, sizeof(mem_buf),
                                "CPU#%d [%s]", cpu->cpu_index,
-                               env->halted ? "halted " : "running");
+                               cpu->halted ? "halted " : "running");
                 memtohex(buf, mem_buf, len);
                 put_packet(s, buf);
             }
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 69c707d332..df44906ef9 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1522,38 +1522,37 @@ passed since 1970, i.e. unix epoch.
 @end table
 ETEXI
 
-HXCOMM Disabled for now, because it isn't built on top of QMP's chardev-add
-HXCOMM     {
-HXCOMM         .name       = "chardev-add",
-HXCOMM         .args_type  = "args:s",
-HXCOMM         .params     = "args",
-HXCOMM         .help       = "add chardev",
-HXCOMM         .mhandler.cmd = hmp_chardev_add,
-HXCOMM     },
-HXCOMM
-HXCOMM STEXI
-HXCOMM @item chardev_add args
-HXCOMM @findex chardev_add
-HXCOMM
-HXCOMM chardev_add accepts the same parameters as the -chardev command line switch.
-HXCOMM
-HXCOMM ETEXI
-HXCOMM
-HXCOMM     {
-HXCOMM         .name       = "chardev-remove",
-HXCOMM         .args_type  = "id:s",
-HXCOMM         .params     = "id",
-HXCOMM         .help       = "remove chardev",
-HXCOMM         .mhandler.cmd = hmp_chardev_remove,
-HXCOMM     },
-HXCOMM
-HXCOMM STEXI
-HXCOMM @item chardev_remove id
-HXCOMM @findex chardev_remove
-HXCOMM
-HXCOMM Removes the chardev @var{id}.
-HXCOMM
-HXCOMM ETEXI
+    {
+        .name       = "chardev-add",
+        .args_type  = "args:s",
+        .params     = "args",
+        .help       = "add chardev",
+        .mhandler.cmd = hmp_chardev_add,
+    },
+
+STEXI
+@item chardev_add args
+@findex chardev_add
+
+chardev_add accepts the same parameters as the -chardev command line switch.
+
+ETEXI
+
+    {
+        .name       = "chardev-remove",
+        .args_type  = "id:s",
+        .params     = "id",
+        .help       = "remove chardev",
+        .mhandler.cmd = hmp_chardev_remove,
+    },
+
+STEXI
+@item chardev_remove id
+@findex chardev_remove
+
+Removes the chardev @var{id}.
+
+ETEXI
 
     {
         .name       = "info",
@@ -1642,6 +1641,8 @@ show device tree
 show qdev device model list
 @item info roms
 show roms
+@item info tpm
+show the TPM device
 @end table
 ETEXI
 
diff --git a/hmp.c b/hmp.c
index 2f47a8a9dd..b0a861cfbb 100644
--- a/hmp.c
+++ b/hmp.c
@@ -607,6 +607,50 @@ void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
     }
 }
 
+void hmp_info_tpm(Monitor *mon, const QDict *qdict)
+{
+    TPMInfoList *info_list, *info;
+    Error *err = NULL;
+    unsigned int c = 0;
+    TPMPassthroughOptions *tpo;
+
+    info_list = qmp_query_tpm(&err);
+    if (err) {
+        monitor_printf(mon, "TPM device not supported\n");
+        error_free(err);
+        return;
+    }
+
+    if (info_list) {
+        monitor_printf(mon, "TPM device:\n");
+    }
+
+    for (info = info_list; info; info = info->next) {
+        TPMInfo *ti = info->value;
+        monitor_printf(mon, " tpm%d: model=%s\n",
+                       c, TpmModel_lookup[ti->model]);
+
+        monitor_printf(mon, "  \\ %s: type=%s",
+                       ti->id, TpmType_lookup[ti->type]);
+
+        switch (ti->tpm_options->kind) {
+        case TPM_TYPE_OPTIONS_KIND_TPM_PASSTHROUGH_OPTIONS:
+            tpo = ti->tpm_options->tpm_passthrough_options;
+            monitor_printf(mon, "%s%s%s%s",
+                           tpo->has_path ? ",path=" : "",
+                           tpo->has_path ? tpo->path : "",
+                           tpo->has_cancel_path ? ",cancel-path=" : "",
+                           tpo->has_cancel_path ? tpo->cancel_path : "");
+            break;
+        case TPM_TYPE_OPTIONS_KIND_MAX:
+            break;
+        }
+        monitor_printf(mon, "\n");
+        c++;
+    }
+    qapi_free_TPMInfoList(info_list);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index 30b3c20ca4..95fe76e218 100644
--- a/hmp.h
+++ b/hmp.h
@@ -36,6 +36,7 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict);
 void hmp_info_balloon(Monitor *mon, const QDict *qdict);
 void hmp_info_pci(Monitor *mon, const QDict *qdict);
 void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
+void hmp_info_tpm(Monitor *mon, const QDict *qdict);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 95571ffc5d..770dc8cf0d 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -62,11 +62,11 @@ static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
 {
     /* If there are any non-masked interrupts, tell the cpu.  */
     if (cpu != NULL) {
-        CPUAlphaState *env = &cpu->env;
+        CPUState *cs = CPU(cpu);
         if (req) {
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
         } else {
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
         }
     }
 }
@@ -358,17 +358,17 @@ static void cchip_write(void *opaque, hwaddr addr,
             for (i = 0; i < 4; ++i) {
                 AlphaCPU *cpu = s->cchip.cpu[i];
                 if (cpu != NULL) {
-                    CPUAlphaState *env = &cpu->env;
+                    CPUState *cs = CPU(cpu);
                     /* IPI can be either cleared or set by the write.  */
                     if (newval & (1 << (i + 8))) {
-                        cpu_interrupt(env, CPU_INTERRUPT_SMP);
+                        cpu_interrupt(cs, CPU_INTERRUPT_SMP);
                     } else {
-                        cpu_reset_interrupt(env, CPU_INTERRUPT_SMP);
+                        cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
                     }
 
                     /* ITI can only be cleared by the write.  */
                     if ((newval & (1 << (i + 4))) == 0) {
-                        cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER);
+                        cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
                     }
                 }
             }
@@ -685,7 +685,7 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level)
                 /* Set the ITI bit for this cpu.  */
                 s->cchip.misc |= 1 << (i + 4);
                 /* And signal the interrupt.  */
-                cpu_interrupt(&cpu->env, CPU_INTERRUPT_TIMER);
+                cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
             }
         }
     }
@@ -698,7 +698,7 @@ static void typhoon_alarm_timer(void *opaque)
 
     /* Set the ITI bit for this cpu.  */
     s->cchip.misc |= 1 << (cpu + 4);
-    cpu_interrupt(&s->cchip.cpu[cpu]->env, CPU_INTERRUPT_TIMER);
+    cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
 }
 
 PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
diff --git a/hw/apic.c b/hw/apic.c
index 8eddba06e5..d2395f04dd 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -151,15 +151,15 @@ static void apic_local_deliver(APICCommonState *s, int vector)
 
     switch ((lvt >> 8) & 7) {
     case APIC_DM_SMI:
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SMI);
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
         break;
 
     case APIC_DM_NMI:
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_NMI);
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
         break;
 
     case APIC_DM_EXTINT:
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
         break;
 
     case APIC_DM_FIXED:
@@ -187,7 +187,7 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
             reset_bit(s->irr, lvt & 0xff);
             /* fall through */
         case APIC_DM_EXTINT:
-            cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
+            cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
             break;
         }
     }
@@ -248,20 +248,20 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
 
         case APIC_DM_SMI:
             foreach_apic(apic_iter, deliver_bitmask,
-                cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_SMI)
+                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
             );
             return;
 
         case APIC_DM_NMI:
             foreach_apic(apic_iter, deliver_bitmask,
-                cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_NMI)
+                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
             );
             return;
 
         case APIC_DM_INIT:
             /* normal INIT IPI sent to processors */
             foreach_apic(apic_iter, deliver_bitmask,
-                         cpu_interrupt(&apic_iter->cpu->env,
+                         cpu_interrupt(CPU(apic_iter->cpu),
                                        CPU_INTERRUPT_INIT)
             );
             return;
@@ -363,15 +363,16 @@ static int apic_irq_pending(APICCommonState *s)
 /* signal the CPU if an irq is pending */
 static void apic_update_irq(APICCommonState *s)
 {
-    CPUState *cpu = CPU(s->cpu);
+    CPUState *cpu;
 
     if (!(s->spurious_vec & APIC_SV_ENABLE)) {
         return;
     }
+    cpu = CPU(s->cpu);
     if (!qemu_cpu_is_self(cpu)) {
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_POLL);
+        cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
     } else if (apic_irq_pending(s) > 0) {
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -478,14 +479,14 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
 static void apic_startup(APICCommonState *s, int vector_num)
 {
     s->sipi_vector = vector_num;
-    cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI);
+    cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
 }
 
 void apic_sipi(DeviceState *d)
 {
     APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
-    cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI);
+    cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
 
     if (!s->wait_for_sipi)
         return;
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 6f0a8ca074..3245c62e68 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -1523,7 +1523,7 @@ static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s,
     omap_clk clk;
 
     if (value & (1 << 11)) {                            /* SETARM_IDLE */
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT);
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
     }
     if (!(value & (1 << 10)))				/* WKUP_MODE */
         qemu_system_shutdown_request();	/* XXX: disable wakeup from IRQ */
@@ -1721,6 +1721,7 @@ static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr,
                                  unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    CPUState *cpu = CPU(s->cpu);
 
     if (size != 2) {
         return omap_badwidth_read16(opaque, addr);
@@ -1737,8 +1738,9 @@ static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr,
         return s->clkm.dsp_rstct2;
 
     case 0x18:	/* DSP_SYSST */
+        cpu = CPU(s->cpu);
         return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start |
-                (s->cpu->env.halted << 6);      /* Quite useless... */
+                (cpu->halted << 6);      /* Quite useless... */
     }
 
     OMAP_BAD_REG(addr);
@@ -3754,9 +3756,10 @@ static void omap_setup_dsp_mapping(MemoryRegion *system_memory,
 void omap_mpu_wakeup(void *opaque, int irq, int req)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
+    CPUState *cpu = CPU(mpu->cpu);
 
-    if (mpu->cpu->env.halted) {
-        cpu_interrupt(&mpu->cpu->env, CPU_INTERRUPT_EXITTB);
+    if (cpu->halted) {
+        cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
     }
 }
 
diff --git a/hw/arm/pic_cpu.c b/hw/arm/pic_cpu.c
index 82236006d2..3a3f06566b 100644
--- a/hw/arm/pic_cpu.c
+++ b/hw/arm/pic_cpu.c
@@ -15,20 +15,22 @@
 static void arm_pic_cpu_handler(void *opaque, int irq, int level)
 {
     ARMCPU *cpu = opaque;
-    CPUARMState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
     switch (irq) {
     case ARM_PIC_CPU_IRQ:
-        if (level)
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
-        else
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        if (level) {
+            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+        } else {
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+        }
         break;
     case ARM_PIC_CPU_FIQ:
-        if (level)
-            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
-        else
-            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
+        if (level) {
+            cpu_interrupt(cs, CPU_INTERRUPT_FIQ);
+        } else {
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ);
+        }
         break;
     default:
         hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index c0f50c90fe..7467cca4f7 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -263,14 +263,14 @@ static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
     case 1:
         /* Idle */
         if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */
-            cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT);
+            cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
             break;
         }
         /* Fall through.  */
 
     case 2:
         /* Deep-Idle */
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT);
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
         s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
         goto message;
 
@@ -301,7 +301,8 @@ static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
 #endif
 
         /* Suspend */
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+        cpu_interrupt(CPU(arm_env_get_cpu(cpu_single_env)),
+                      CPU_INTERRUPT_HALT);
 
         goto message;
 
diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c
index eef8411e86..55ebcd724a 100644
--- a/hw/arm/pxa2xx_gpio.c
+++ b/hw/arm/pxa2xx_gpio.c
@@ -93,6 +93,7 @@ static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
 static void pxa2xx_gpio_set(void *opaque, int line, int level)
 {
     PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
+    CPUState *cpu = CPU(s->cpu);
     int bank;
     uint32_t mask;
 
@@ -118,8 +119,8 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level)
         pxa2xx_gpio_irq_update(s);
 
     /* Wake-up GPIOs */
-    if (s->cpu->env.halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) {
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB);
+    if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) {
+        cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
     }
 }
 
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
index 145fc78c2f..25e90895e1 100644
--- a/hw/arm/pxa2xx_pic.c
+++ b/hw/arm/pxa2xx_pic.c
@@ -46,12 +46,13 @@ static void pxa2xx_pic_update(void *opaque)
 {
     uint32_t mask[2];
     PXA2xxPICState *s = (PXA2xxPICState *) opaque;
+    CPUState *cpu = CPU(s->cpu);
 
-    if (s->cpu->env.halted) {
+    if (cpu->halted) {
         mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
         mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
         if (mask[0] || mask[1]) {
-            cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB);
+            cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
         }
     }
 
@@ -59,15 +60,15 @@ static void pxa2xx_pic_update(void *opaque)
     mask[1] = s->int_pending[1] & s->int_enabled[1];
 
     if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) {
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ);
+        cpu_interrupt(cpu, CPU_INTERRUPT_FIQ);
     } else {
-        cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ);
+        cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ);
     }
 
     if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) {
-        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
     } else {
-        cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
     }
 }
 
diff --git a/hw/cris/pic_cpu.c b/hw/cris/pic_cpu.c
index 7f50471e53..85c68c0497 100644
--- a/hw/cris/pic_cpu.c
+++ b/hw/cris/pic_cpu.c
@@ -30,16 +30,18 @@
 
 static void cris_pic_cpu_handler(void *opaque, int irq, int level)
 {
-    CPUCRISState *env = (CPUCRISState *)opaque;
+    CRISCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
     int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
 
-    if (level)
-        cpu_interrupt(env, type);
-    else
-        cpu_reset_interrupt(env, type);
+    if (level) {
+        cpu_interrupt(cs, type);
+    } else {
+        cpu_reset_interrupt(cs, type);
+    }
 }
 
 qemu_irq *cris_pic_init_cpu(CPUCRISState *env)
 {
-    return qemu_allocate_irqs(cris_pic_cpu_handler, env, 2);
+    return qemu_allocate_irqs(cris_pic_cpu_handler, cris_env_get_cpu(env), 2);
 }
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 309bb83cab..ed7d9badb5 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -190,10 +190,12 @@ static void pic_irq_request(void *opaque, int irq, int level)
             env = env->next_cpu;
         }
     } else {
-        if (level)
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
-        else
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        CPUState *cs = CPU(x86_env_get_cpu(env));
+        if (level) {
+            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+        } else {
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+        }
     }
 }
 
@@ -854,10 +856,10 @@ DeviceState *cpu_get_current_apic(void)
 
 void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
 {
-    CPUX86State *s = opaque;
+    X86CPU *cpu = opaque;
 
     if (level) {
-        cpu_interrupt(s, CPU_INTERRUPT_SMI);
+        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_SMI);
     }
 }
 
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 0ee3b3b806..0abc9f11e3 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -205,7 +205,8 @@ static void pc_init1(MemoryRegion *system_memory,
     if (pci_enabled && acpi_enabled) {
         i2c_bus *smbus;
 
-        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt,
+                                     x86_env_get_cpu(first_cpu), 1);
         /* TODO: Populate SPD eeprom data.  */
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
                               gsi[9], *smi_irq,
diff --git a/hw/i386/xen_machine_pv.c b/hw/i386/xen_machine_pv.c
index a8177b6340..37ba34e5a9 100644
--- a/hw/i386/xen_machine_pv.c
+++ b/hw/i386/xen_machine_pv.c
@@ -36,7 +36,7 @@ static void xen_init_pv(QEMUMachineInitArgs *args)
     const char *kernel_cmdline = args->kernel_cmdline;
     const char *initrd_filename = args->initrd_filename;
     X86CPU *cpu;
-    CPUX86State *env;
+    CPUState *cs;
     DriveInfo *dinfo;
     int i;
 
@@ -49,8 +49,8 @@ static void xen_init_pv(QEMUMachineInitArgs *args)
 #endif
     }
     cpu = cpu_x86_init(cpu_model);
-    env = &cpu->env;
-    env->halted = 1;
+    cs = CPU(cpu);
+    cs->halted = 1;
 
     /* Initialize backend core & drivers */
     if (xen_be_init() != 0) {
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
index 1ce466a1b1..db92948092 100644
--- a/hw/lm32/lm32_boards.c
+++ b/hw/lm32/lm32_boards.c
@@ -41,12 +41,13 @@ typedef struct {
 
 static void cpu_irq_handler(void *opaque, int irq, int level)
 {
-    CPULM32State *env = opaque;
+    LM32CPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
 
     if (level) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -117,7 +118,7 @@ static void lm32_evr_init(QEMUMachineInitArgs *args)
                           0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
 
     /* create irq lines */
-    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1);
     env->pic_state = lm32_pic_init(*cpu_irq);
     for (i = 0; i < 32; i++) {
         irq[i] = qdev_get_gpio_in(env->pic_state, i);
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
index fd36de57b5..b347cf964c 100644
--- a/hw/lm32/milkymist.c
+++ b/hw/lm32/milkymist.c
@@ -46,12 +46,13 @@ typedef struct {
 
 static void cpu_irq_handler(void *opaque, int irq, int level)
 {
-    CPULM32State *env = opaque;
+    LM32CPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
 
     if (level) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -123,7 +124,7 @@ milkymist_init(QEMUMachineInitArgs *args)
                           0x00, 0x89, 0x00, 0x1d, 1);
 
     /* create irq lines */
-    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1);
     env->pic_state = lm32_pic_init(*cpu_irq);
     for (i = 0; i < 32; i++) {
         irq[i] = qdev_get_gpio_in(env->pic_state, i);
diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c
index 0ca0a59ef7..ff0a3092d5 100644
--- a/hw/lpc_ich9.c
+++ b/hw/lpc_ich9.c
@@ -381,7 +381,7 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
 
     /* SMI_EN = PMBASE + 30. SMI control and enable register */
     if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
-        cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
+        cpu_interrupt(CPU(x86_env_get_cpu(first_cpu)), CPU_INTERRUPT_SMI);
     }
 }
 
diff --git a/hw/microblaze/pic_cpu.c b/hw/microblaze/pic_cpu.c
index d4743ab390..6248de92bb 100644
--- a/hw/microblaze/pic_cpu.c
+++ b/hw/microblaze/pic_cpu.c
@@ -29,16 +29,19 @@
 
 static void microblaze_pic_cpu_handler(void *opaque, int irq, int level)
 {
-    CPUMBState *env = (CPUMBState *)opaque;
+    MicroBlazeCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
     int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
 
-    if (level)
-        cpu_interrupt(env, type);
-    else
-        cpu_reset_interrupt(env, type);
+    if (level) {
+        cpu_interrupt(cs, type);
+    } else {
+        cpu_reset_interrupt(cs, type);
+    }
 }
 
 qemu_irq *microblaze_pic_init_cpu(CPUMBState *env)
 {
-    return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2);
+    return qemu_allocate_irqs(microblaze_pic_cpu_handler, mb_env_get_cpu(env),
+                              2);
 }
diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c
index ddd3b1bb01..0e5e86699c 100644
--- a/hw/mips/mips_int.c
+++ b/hw/mips/mips_int.c
@@ -26,7 +26,9 @@
 
 static void cpu_mips_irq_request(void *opaque, int irq, int level)
 {
-    CPUMIPSState *env = (CPUMIPSState *)opaque;
+    MIPSCPU *cpu = opaque;
+    CPUMIPSState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
     if (irq < 0 || irq > 7)
         return;
@@ -38,9 +40,9 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level)
     }
 
     if (env->CP0_Cause & CP0Ca_IP_mask) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -49,7 +51,7 @@ void cpu_mips_irq_init_cpu(CPUMIPSState *env)
     qemu_irq *qi;
     int i;
 
-    qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8);
+    qi = qemu_allocate_irqs(cpu_mips_irq_request, mips_env_get_cpu(env), 8);
     for (i = 0; i < 8; i++) {
         env->irq[i] = qi[i];
     }
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
index f6c877f425..4144b34be7 100644
--- a/hw/openrisc/cputimer.c
+++ b/hw/openrisc/cputimer.c
@@ -73,8 +73,10 @@ static void openrisc_timer_cb(void *opaque)
 
     if ((cpu->env.ttmr & TTMR_IE) &&
          qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) {
+        CPUState *cs = CPU(cpu);
+
         cpu->env.ttmr |= TTMR_IP;
-        cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER;
+        cs->interrupt_request |= CPU_INTERRUPT_TIMER;
     }
 
     switch (cpu->env.ttmr & TTMR_M) {
diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c
index 931511ec0f..ca0b7c11bd 100644
--- a/hw/openrisc/pic_cpu.c
+++ b/hw/openrisc/pic_cpu.c
@@ -25,6 +25,7 @@
 static void openrisc_pic_cpu_handler(void *opaque, int irq, int level)
 {
     OpenRISCCPU *cpu = (OpenRISCCPU *)opaque;
+    CPUState *cs = CPU(cpu);
     int i;
     uint32_t irq_bit = 1 << irq;
 
@@ -40,9 +41,9 @@ static void openrisc_pic_cpu_handler(void *opaque, int irq, int level)
 
     for (i = 0; i < 32; i++) {
         if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) {
-            cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD);
+            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
         } else {
-            cpu_reset_interrupt(&cpu->env, CPU_INTERRUPT_HARD);
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
             cpu->env.picsr &= ~(1 << i);
         }
     }
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 451682cb83..fef9c5d842 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -420,26 +420,28 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env)
 static void ppce500_cpu_reset_sec(void *opaque)
 {
     PowerPCCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
 
-    cpu_reset(CPU(cpu));
+    cpu_reset(cs);
 
     /* Secondary CPU starts in halted state for now. Needs to change when
        implementing non-kernel boot. */
-    env->halted = 1;
+    cs->halted = 1;
     env->exception_index = EXCP_HLT;
 }
 
 static void ppce500_cpu_reset(void *opaque)
 {
     PowerPCCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     struct boot_info *bi = env->load_info;
 
-    cpu_reset(CPU(cpu));
+    cpu_reset(cs);
 
     /* Set initial guest state. */
-    env->halted = 0;
+    cs->halted = 0;
     env->gpr[1] = (16<<20) - 8;
     env->gpr[3] = bi->dt_base;
     env->nip = bi->entry;
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index c9437fc6a7..85bc821d94 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -52,16 +52,18 @@ static void cpu_ppc_tb_start (CPUPPCState *env);
 
 void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
 {
+    CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     unsigned int old_pending = env->pending_interrupts;
 
     if (level) {
         env->pending_interrupts |= 1 << n_IRQ;
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
         env->pending_interrupts &= ~(1 << n_IRQ);
-        if (env->pending_interrupts == 0)
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        if (env->pending_interrupts == 0) {
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+        }
     }
 
     if (old_pending != env->pending_interrupts) {
@@ -72,7 +74,7 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
 
     LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
                 "req %08x\n", __func__, env, n_IRQ, level,
-                env->pending_interrupts, env->interrupt_request);
+                env->pending_interrupts, CPU(cpu)->interrupt_request);
 }
 
 /* PowerPC 6xx / 7xx internal IRQ controller */
@@ -87,6 +89,8 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level)
     cur_level = (env->irq_input_state >> pin) & 1;
     /* Don't generate spurious events */
     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        CPUState *cs = CPU(cpu);
+
         switch (pin) {
         case PPC6xx_INPUT_TBEN:
             /* Level sensitive - active high */
@@ -126,14 +130,14 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level)
             /* XXX: Note that the only way to restart the CPU is to reset it */
             if (level) {
                 LOG_IRQ("%s: stop the CPU\n", __func__);
-                env->halted = 1;
+                cs->halted = 1;
             }
             break;
         case PPC6xx_INPUT_HRESET:
             /* Level sensitive - active low */
             if (level) {
                 LOG_IRQ("%s: reset the CPU\n", __func__);
-                cpu_interrupt(env, CPU_INTERRUPT_RESET);
+                cpu_interrupt(cs, CPU_INTERRUPT_RESET);
             }
             break;
         case PPC6xx_INPUT_SRESET:
@@ -174,6 +178,8 @@ static void ppc970_set_irq(void *opaque, int pin, int level)
     cur_level = (env->irq_input_state >> pin) & 1;
     /* Don't generate spurious events */
     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        CPUState *cs = CPU(cpu);
+
         switch (pin) {
         case PPC970_INPUT_INT:
             /* Level sensitive - active high */
@@ -203,17 +209,17 @@ static void ppc970_set_irq(void *opaque, int pin, int level)
             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
             if (level) {
                 LOG_IRQ("%s: stop the CPU\n", __func__);
-                env->halted = 1;
+                cs->halted = 1;
             } else {
                 LOG_IRQ("%s: restart the CPU\n", __func__);
-                env->halted = 0;
-                qemu_cpu_kick(CPU(cpu));
+                cs->halted = 0;
+                qemu_cpu_kick(cs);
             }
             break;
         case PPC970_INPUT_HRESET:
             /* Level sensitive - active low */
             if (level) {
-                cpu_interrupt(env, CPU_INTERRUPT_RESET);
+                cpu_interrupt(cs, CPU_INTERRUPT_RESET);
             }
             break;
         case PPC970_INPUT_SRESET:
@@ -295,6 +301,8 @@ static void ppc40x_set_irq(void *opaque, int pin, int level)
     cur_level = (env->irq_input_state >> pin) & 1;
     /* Don't generate spurious events */
     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        CPUState *cs = CPU(cpu);
+
         switch (pin) {
         case PPC40x_INPUT_RESET_SYS:
             if (level) {
@@ -332,11 +340,11 @@ static void ppc40x_set_irq(void *opaque, int pin, int level)
             /* Level sensitive - active low */
             if (level) {
                 LOG_IRQ("%s: stop the CPU\n", __func__);
-                env->halted = 1;
+                cs->halted = 1;
             } else {
                 LOG_IRQ("%s: restart the CPU\n", __func__);
-                env->halted = 0;
-                qemu_cpu_kick(CPU(cpu));
+                cs->halted = 0;
+                qemu_cpu_kick(cs);
             }
             break;
         case PPC40x_INPUT_DEBUG:
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 8465f6dcd4..56bae8f6e0 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -1776,7 +1776,7 @@ void ppc40x_core_reset(PowerPCCPU *cpu)
     target_ulong dbsr;
 
     printf("Reset PowerPC core\n");
-    cpu_interrupt(env, CPU_INTERRUPT_RESET);
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
     dbsr = env->spr[SPR_40x_DBSR];
     dbsr &= ~0x00000300;
     dbsr |= 0x00000100;
@@ -1789,7 +1789,7 @@ void ppc40x_chip_reset(PowerPCCPU *cpu)
     target_ulong dbsr;
 
     printf("Reset PowerPC chip\n");
-    cpu_interrupt(env, CPU_INTERRUPT_RESET);
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
     /* XXX: TODO reset all internal peripherals */
     dbsr = env->spr[SPR_40x_DBSR];
     dbsr &= ~0x00000300;
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index d904fbe176..1290d37bb9 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -112,7 +112,7 @@ static void spin_kick(void *data)
     map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
     mmubooke_create_initial_mapping(env, 0, map_start, map_size);
 
-    env->halted = 0;
+    cpu->halted = 0;
     env->exception_index = -1;
     cpu->stopped = false;
     qemu_cpu_kick(cpu);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index fd2411310c..f355a9bb84 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -617,6 +617,8 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
 
 static void ppc_spapr_reset(void)
 {
+    CPUState *first_cpu_cpu;
+
     /* Reset the hash table & recalc the RMA */
     spapr_reset_htab(spapr);
 
@@ -627,9 +629,10 @@ static void ppc_spapr_reset(void)
                        spapr->rtas_size);
 
     /* Set up the entry state */
+    first_cpu_cpu = CPU(first_cpu);
     first_cpu->gpr[3] = spapr->fdt_addr;
     first_cpu->gpr[5] = 0;
-    first_cpu->halted = 0;
+    first_cpu_cpu->halted = 0;
     first_cpu->nip = spapr->entry_point;
 
 }
@@ -637,14 +640,15 @@ static void ppc_spapr_reset(void)
 static void spapr_cpu_reset(void *opaque)
 {
     PowerPCCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
 
-    cpu_reset(CPU(cpu));
+    cpu_reset(cs);
 
     /* All CPUs start halted.  CPU0 is unhalted from the machine level
      * reset code and the rest are explicitly started up by the guest
      * using an RTAS call */
-    env->halted = 1;
+    cs->halted = 1;
 
     env->spr[SPR_HIOR] = 0;
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 77c052fcb1..dd72743b52 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -543,7 +543,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
     env->msr |= (1ULL << MSR_EE);
     hreg_compute_hflags(env);
     if (!cpu_has_work(cs)) {
-        env->halted = 1;
+        cs->halted = 1;
         env->exception_index = EXCP_HLT;
         cs->exit_request = 1;
     }
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 5ec787f29d..a24e853d4d 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -145,7 +145,7 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
             continue;
         }
 
-        if (env->halted) {
+        if (cpu->halted) {
             rtas_st(rets, 1, 0);
         } else {
             rtas_st(rets, 1, 2);
@@ -184,7 +184,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr,
             continue;
         }
 
-        if (!env->halted) {
+        if (!cpu->halted) {
             rtas_st(rets, 0, -1);
             return;
         }
@@ -197,7 +197,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr,
         env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
         env->nip = start;
         env->gpr[3] = r3;
-        env->halted = 0;
+        cpu->halted = 0;
 
         qemu_cpu_kick(cpu);
 
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index e25c330320..ca275bd9d7 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -132,23 +132,25 @@ static unsigned s390_running_cpus;
 
 void s390_add_running_cpu(S390CPU *cpu)
 {
+    CPUState *cs = CPU(cpu);
     CPUS390XState *env = &cpu->env;
 
-    if (env->halted) {
+    if (cs->halted) {
         s390_running_cpus++;
-        env->halted = 0;
+        cs->halted = 0;
         env->exception_index = -1;
     }
 }
 
 unsigned s390_del_running_cpu(S390CPU *cpu)
 {
+    CPUState *cs = CPU(cpu);
     CPUS390XState *env = &cpu->env;
 
-    if (env->halted == 0) {
+    if (cs->halted == 0) {
         assert(s390_running_cpus >= 1);
         s390_running_cpus--;
-        env->halted = 1;
+        cs->halted = 1;
         env->exception_index = EXCP_HLT;
     }
     return s390_running_cpus;
@@ -183,11 +185,13 @@ void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys)
 
     for (i = 0; i < smp_cpus; i++) {
         S390CPU *cpu;
+        CPUState *cs;
 
         cpu = cpu_s390x_init(cpu_model);
+        cs = CPU(cpu);
 
         ipi_states[i] = cpu;
-        cpu->env.halted = 1;
+        cs->halted = 1;
         cpu->env.exception_index = EXCP_HLT;
         cpu->env.storage_keys = storage_keys;
     }
diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c
index 6778c94f8e..e4d37ad6ac 100644
--- a/hw/sh4/sh7750.c
+++ b/hw/sh4/sh7750.c
@@ -255,6 +255,7 @@ static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr)
 static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr)
 {
     SH7750State *s = opaque;
+    SuperHCPUClass *scc;
 
     switch (addr) {
     case SH7750_BCR1_A7:
@@ -288,11 +289,14 @@ static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr)
     case SH7750_CCR_A7:
 	return s->ccr;
     case 0x1f000030:		/* Processor version */
-	return s->cpu->pvr;
+        scc = SUPERH_CPU_GET_CLASS(s->cpu);
+        return scc->pvr;
     case 0x1f000040:		/* Cache version */
-	return s->cpu->cvr;
+        scc = SUPERH_CPU_GET_CLASS(s->cpu);
+        return scc->cvr;
     case 0x1f000044:		/* Processor revision */
-	return s->cpu->prr;
+        scc = SUPERH_CPU_GET_CLASS(s->cpu);
+        return scc->prr;
     default:
 	error_access("long read", addr);
         abort();
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
index 9e64e4d353..29e3d8f127 100644
--- a/hw/sh_intc.c
+++ b/hw/sh_intc.c
@@ -42,15 +42,17 @@ void sh_intc_toggle_source(struct intc_source *source,
         pending_changed = 1;
 
     if (pending_changed) {
+        CPUState *cpu = CPU(sh_env_get_cpu(first_cpu));
         if (source->pending) {
             source->parent->pending++;
-	    if (source->parent->pending == 1)
-                cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
-	}
-	else {
+            if (source->parent->pending == 1) {
+                cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
+            }
+        } else {
             source->parent->pending--;
-	    if (source->parent->pending == 0)
-                cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
+            if (source->parent->pending == 0) {
+                cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
+            }
 	}
     }
 
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index f58061f8ed..bf06bf4b51 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -49,11 +49,12 @@ typedef struct ResetData {
 static void main_cpu_reset(void *opaque)
 {
     ResetData *s   = (ResetData *)opaque;
+    CPUState *cpu = CPU(s->cpu);
     CPUSPARCState  *env = &s->cpu->env;
 
-    cpu_reset(CPU(s->cpu));
+    cpu_reset(cpu);
 
-    env->halted = 0;
+    cpu->halted = 0;
     env->pc     = s->entry;
     env->npc    = s->entry + 4;
 }
@@ -66,6 +67,7 @@ void leon3_irq_ack(void *irq_manager, int intno)
 static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
 {
     CPUSPARCState *env = (CPUSPARCState *)opaque;
+    CPUState *cs;
 
     assert(env != NULL);
 
@@ -81,16 +83,18 @@ static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
 
                 env->interrupt_index = TT_EXTINT | i;
                 if (old_interrupt != env->interrupt_index) {
+                    cs = CPU(sparc_env_get_cpu(env));
                     trace_leon3_set_irq(i);
-                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                    cpu_interrupt(cs, CPU_INTERRUPT_HARD);
                 }
                 break;
             }
         }
     } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        cs = CPU(sparc_env_get_cpu(env));
         trace_leon3_reset_irq(env->interrupt_index & 15);
         env->interrupt_index = 0;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
 
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 37bd04108d..2f214da557 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -230,6 +230,8 @@ void sun4m_irq_info(Monitor *mon, const QDict *qdict)
 
 void cpu_check_irqs(CPUSPARCState *env)
 {
+    CPUState *cs;
+
     if (env->pil_in && (env->interrupt_index == 0 ||
                         (env->interrupt_index & ~15) == TT_EXTINT)) {
         unsigned int i;
@@ -240,26 +242,29 @@ void cpu_check_irqs(CPUSPARCState *env)
 
                 env->interrupt_index = TT_EXTINT | i;
                 if (old_interrupt != env->interrupt_index) {
+                    cs = CPU(sparc_env_get_cpu(env));
                     trace_sun4m_cpu_interrupt(i);
-                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                    cpu_interrupt(cs, CPU_INTERRUPT_HARD);
                 }
                 break;
             }
         }
     } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        cs = CPU(sparc_env_get_cpu(env));
         trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15);
         env->interrupt_index = 0;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
 
 static void cpu_kick_irq(SPARCCPU *cpu)
 {
     CPUSPARCState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
-    env->halted = 0;
+    cs->halted = 0;
     cpu_check_irqs(env);
-    qemu_cpu_kick(CPU(cpu));
+    qemu_cpu_kick(cs);
 }
 
 static void cpu_set_irq(void *opaque, int irq, int level)
@@ -285,25 +290,27 @@ static void dummy_cpu_set_irq(void *opaque, int irq, int level)
 static void main_cpu_reset(void *opaque)
 {
     SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
-    cpu_reset(CPU(cpu));
-    env->halted = 0;
+    cpu_reset(cs);
+    cs->halted = 0;
 }
 
 static void secondary_cpu_reset(void *opaque)
 {
     SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
-    cpu_reset(CPU(cpu));
-    env->halted = 1;
+    cpu_reset(cs);
+    cs->halted = 1;
 }
 
 static void cpu_halt_signal(void *opaque, int irq, int level)
 {
-    if (level && cpu_single_env)
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+    if (level && cpu_single_env) {
+        cpu_interrupt(CPU(sparc_env_get_cpu(cpu_single_env)),
+                      CPU_INTERRUPT_HALT);
+    }
 }
 
 static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
@@ -826,6 +833,7 @@ static const TypeInfo ram_info = {
 static void cpu_devinit(const char *cpu_model, unsigned int id,
                         uint64_t prom_addr, qemu_irq **cpu_irqs)
 {
+    CPUState *cs;
     SPARCCPU *cpu;
     CPUSPARCState *env;
 
@@ -841,7 +849,8 @@ static void cpu_devinit(const char *cpu_model, unsigned int id,
         qemu_register_reset(main_cpu_reset, cpu);
     } else {
         qemu_register_reset(secondary_cpu_reset, cpu);
-        env->halted = 1;
+        cs = CPU(cpu);
+        cs->halted = 1;
     }
     *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS);
     env->prom_addr = prom_addr;
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 51ffa1c09b..4c39cf6607 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -254,6 +254,7 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
 
 void cpu_check_irqs(CPUSPARCState *env)
 {
+    CPUState *cs;
     uint32_t pil = env->pil_in |
                   (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
 
@@ -261,6 +262,7 @@ void cpu_check_irqs(CPUSPARCState *env)
     if (env->ivec_status & 0x20) {
         return;
     }
+    cs = CPU(sparc_env_get_cpu(env));
     /* check if TM or SM in SOFTINT are set
        setting these also causes interrupt 14 */
     if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
@@ -270,11 +272,11 @@ void cpu_check_irqs(CPUSPARCState *env)
     /* The bit corresponding to psrpil is (1<< psrpil), the next bit
        is (2 << psrpil). */
     if (pil < (2 << env->psrpil)){
-        if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+        if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
             CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
                            env->interrupt_index);
             env->interrupt_index = 0;
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
         }
         return;
     }
@@ -297,50 +299,54 @@ void cpu_check_irqs(CPUSPARCState *env)
                     env->interrupt_index = new_interrupt;
                     CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
                                    old_interrupt, new_interrupt);
-                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                    cpu_interrupt(cs, CPU_INTERRUPT_HARD);
                 }
                 break;
             }
         }
-    } else if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+    } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
         CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
                        "current interrupt %x\n",
                        pil, env->pil_in, env->softint, env->interrupt_index);
         env->interrupt_index = 0;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
 
 static void cpu_kick_irq(SPARCCPU *cpu)
 {
+    CPUState *cs = CPU(cpu);
     CPUSPARCState *env = &cpu->env;
 
-    env->halted = 0;
+    cs->halted = 0;
     cpu_check_irqs(env);
-    qemu_cpu_kick(CPU(cpu));
+    qemu_cpu_kick(cs);
 }
 
 static void cpu_set_ivec_irq(void *opaque, int irq, int level)
 {
     SPARCCPU *cpu = opaque;
     CPUSPARCState *env = &cpu->env;
+    CPUState *cs;
 
     if (level) {
         if (!(env->ivec_status & 0x20)) {
             CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
-            env->halted = 0;
+            cs = CPU(cpu);
+            cs->halted = 0;
             env->interrupt_index = TT_IVEC;
             env->ivec_status |= 0x20;
             env->ivec_data[0] = (0x1f << 6) | irq;
             env->ivec_data[1] = 0;
             env->ivec_data[2] = 0;
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
         }
     } else {
         if (env->ivec_status & 0x20) {
             CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
+            cs = CPU(cpu);
             env->ivec_status &= ~0x20;
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
         }
     }
 }
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index f9d0c2bab1..78ab13f9ed 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -26,13 +26,14 @@
 
 static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
 {
-    CPUUniCore32State *env = opaque;
+    UniCore32CPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
 
     assert(irq == 0);
     if (level) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -44,7 +45,8 @@ static void puv3_soc_init(CPUUniCore32State *env)
     int i;
 
     /* Initialize interrupt controller */
-    cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1);
+    cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler,
+                                  uc32_env_get_cpu(env), 1);
     dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
     for (i = 0; i < PUV3_IRQS_NR; i++) {
         irqs[i] = qdev_get_gpio_in(dev, i);
diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c
index f485a1465c..7f015ff5ab 100644
--- a/hw/xtensa/pic_cpu.c
+++ b/hw/xtensa/pic_cpu.c
@@ -47,6 +47,7 @@ void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
 
 void check_interrupts(CPUXtensaState *env)
 {
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
     int minlevel = xtensa_get_cintlevel(env);
     uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
     int level;
@@ -54,7 +55,7 @@ void check_interrupts(CPUXtensaState *env)
     /* If the CPU is halted advance CCOUNT according to the vm_clock time
      * elapsed since the moment when it was advanced last time.
      */
-    if (env->halted) {
+    if (cs->halted) {
         int64_t now = qemu_get_clock_ns(vm_clock);
 
         xtensa_advance_ccount(env,
@@ -65,7 +66,7 @@ void check_interrupts(CPUXtensaState *env)
     for (level = env->config->nlevel; level > minlevel; --level) {
         if (env->config->level_mask[level] & int_set_enabled) {
             env->pending_irq_level = level;
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
             qemu_log_mask(CPU_LOG_INT,
                     "%s level = %d, cintlevel = %d, "
                     "pc = %08x, a0 = %08x, ps = %08x, "
@@ -79,7 +80,7 @@ void check_interrupts(CPUXtensaState *env)
         }
     }
     env->pending_irq_level = 0;
-    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
 
 static void xtensa_set_irq(void *opaque, int irq, int active)
@@ -127,11 +128,12 @@ static void xtensa_ccompare_cb(void *opaque)
 {
     XtensaCPU *cpu = opaque;
     CPUXtensaState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
-    if (env->halted) {
+    if (cs->halted) {
         env->halt_clock = qemu_get_clock_ns(vm_clock);
         xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
-        if (!cpu_has_work(CPU(cpu))) {
+        if (!cpu_has_work(cs)) {
             env->sregs[CCOUNT] = env->wake_ccount + 1;
             xtensa_rearm_ccompare_timer(env);
         }
diff --git a/include/char/char.h b/include/char/char.h
index 2e24270895..d6a03513bf 100644
--- a/include/char/char.h
+++ b/include/char/char.h
@@ -245,6 +245,8 @@ CharDriverState *qemu_chr_find(const char *name);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
 void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *));
+void register_char_driver_qapi(const char *name, int kind,
+        void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp));
 
 /* add an eventfd to the qemu devices that are polled */
 CharDriverState *qemu_chr_open_eventfd(int eventfd);
@@ -259,4 +261,10 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr);
 
 CharDriverState *qemu_char_get_next_serial(void);
 
+/* msmouse */
+CharDriverState *qemu_chr_open_msmouse(void);
+
+/* baum.c */
+CharDriverState *chr_baum_init(void);
+
 #endif
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 249e0464f2..e9c3717863 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -421,21 +421,6 @@ DECLARE_TLS(CPUArchState *,cpu_single_env);
      | CPU_INTERRUPT_TGT_EXT_3   \
      | CPU_INTERRUPT_TGT_EXT_4)
 
-#ifndef CONFIG_USER_ONLY
-typedef void (*CPUInterruptHandler)(CPUArchState *, int);
-
-extern CPUInterruptHandler cpu_interrupt_handler;
-
-static inline void cpu_interrupt(CPUArchState *s, int mask)
-{
-    cpu_interrupt_handler(s, mask);
-}
-#else /* USER_ONLY */
-void cpu_interrupt(CPUArchState *env, int mask);
-#endif /* USER_ONLY */
-
-void cpu_reset_interrupt(CPUArchState *env, int mask);
-
 void cpu_exit(CPUArchState *s);
 
 /* Breakpoint/watchpoint flags */
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 3dc96568ac..0ae967ae20 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -156,8 +156,6 @@ typedef struct CPUWatchpoint {
                             accessed */                                 \
     target_ulong mem_io_vaddr; /* target virtual addr at which the      \
                                      memory was accessed */             \
-    uint32_t halted; /* Nonzero if the CPU is in suspend state */       \
-    uint32_t interrupt_request;                                         \
     CPU_COMMON_TLB                                                      \
     struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];           \
     /* buffer for temporaries in the code generator */                  \
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index a64db941bc..6666d27b25 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -134,6 +134,10 @@ struct VMStateDescription {
     const VMStateSubsection *subsections;
 };
 
+#ifdef CONFIG_USER_ONLY
+extern const VMStateDescription vmstate_dummy;
+#endif
+
 extern const VMStateInfo vmstate_info_bool;
 
 extern const VMStateInfo vmstate_info_int8;
@@ -638,12 +642,20 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id);
 void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                         void *opaque);
-int vmstate_register(DeviceState *dev, int instance_id,
-                     const VMStateDescription *vmsd, void *base);
+
 int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
                                    const VMStateDescription *vmsd,
                                    void *base, int alias_id,
                                    int required_for_version);
+
+static inline int vmstate_register(DeviceState *dev, int instance_id,
+                                   const VMStateDescription *vmsd,
+                                   void *opaque)
+{
+    return vmstate_register_with_alias_id(dev, instance_id, vmsd,
+                                          opaque, -1, 0);
+}
+
 void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
                         void *opaque);
 
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 6125bf7bdf..ae5c21cba3 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -38,6 +38,7 @@ int socket_set_nodelay(int fd);
 void socket_set_block(int fd);
 void socket_set_nonblock(int fd);
 int send_all(int fd, const void *buf, int len1);
+int recv_all(int fd, void *buf, int len1, bool single_read);
 
 /* callback function for nonblocking connect
  * valid fd on success, negative error code on failure
@@ -70,6 +71,7 @@ SocketAddress *socket_parse(const char *str, Error **errp);
 int socket_connect(SocketAddress *addr, Error **errp,
                    NonBlockingConnectHandler *callback, void *opaque);
 int socket_listen(SocketAddress *addr, Error **errp);
+int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp);
 
 /* Old, ipv4 only bits.  Don't use for new code. */
 int parse_host_port(struct sockaddr_in *saddr, const char *str);
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index ab2657c558..3664a1b631 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -44,6 +44,8 @@ typedef struct CPUState CPUState;
  * @class_by_name: Callback to map -cpu command line model name to an
  * instantiatable CPU type.
  * @reset: Callback to reset the #CPUState to its initial state.
+ * @do_interrupt: Callback for interrupt handling.
+ * @vmsd: State description for migration.
  *
  * Represents a CPU family or model.
  */
@@ -55,6 +57,9 @@ typedef struct CPUClass {
     ObjectClass *(*class_by_name)(const char *cpu_model);
 
     void (*reset)(CPUState *cpu);
+    void (*do_interrupt)(CPUState *cpu);
+
+    const struct VMStateDescription *vmsd;
 } CPUClass;
 
 struct KVMState;
@@ -69,6 +74,8 @@ struct kvm_run;
  * @host_tid: Host thread ID.
  * @running: #true if CPU is currently running (usermode).
  * @created: Indicates whether the CPU thread has been successfully created.
+ * @interrupt_request: Indicates a pending interrupt request.
+ * @halted: Nonzero if the CPU is in suspended state.
  * @stop: Indicates a pending stop request.
  * @stopped: Indicates the CPU has been artificially stopped.
  * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this
@@ -103,6 +110,7 @@ struct CPUState {
     bool stopped;
     volatile sig_atomic_t exit_request;
     volatile sig_atomic_t tcg_exit_req;
+    uint32_t interrupt_request;
 
     void *env_ptr; /* CPUArchState */
     struct TranslationBlock *current_tb;
@@ -114,6 +122,7 @@ struct CPUState {
 
     /* TODO Move common fields from CPUArchState here. */
     int cpu_index; /* used by alpha TCG */
+    uint32_t halted; /* used by alpha, cris, ppc TCG */
 };
 
 
@@ -135,6 +144,27 @@ void cpu_reset(CPUState *cpu);
 ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model);
 
 /**
+ * cpu_class_set_vmsd:
+ * @cc: CPU class
+ * @value: Value to set. Unused for %CONFIG_USER_ONLY.
+ *
+ * Sets #VMStateDescription for @cc.
+ *
+ * The @value argument is intentionally discarded for the non-softmmu targets
+ * to avoid linker errors or excessive preprocessor usage. If this behavior
+ * is undesired, you should assign #CPUState.vmsd directly instead.
+ */
+#ifndef CONFIG_USER_ONLY
+static inline void cpu_class_set_vmsd(CPUClass *cc,
+                                      const struct VMStateDescription *value)
+{
+    cc->vmsd = value;
+}
+#else
+#define cpu_class_set_vmsd(cc, value) ((cc)->vmsd = NULL)
+#endif
+
+/**
  * qemu_cpu_has_work:
  * @cpu: The vCPU to check.
  *
@@ -193,5 +223,38 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data);
  */
 CPUState *qemu_get_cpu(int index);
 
+#ifndef CONFIG_USER_ONLY
+
+typedef void (*CPUInterruptHandler)(CPUState *, int);
+
+extern CPUInterruptHandler cpu_interrupt_handler;
+
+/**
+ * cpu_interrupt:
+ * @cpu: The CPU to set an interrupt on.
+ * @mask: The interupts to set.
+ *
+ * Invokes the interrupt handler.
+ */
+static inline void cpu_interrupt(CPUState *cpu, int mask)
+{
+    cpu_interrupt_handler(cpu, mask);
+}
+
+#else /* USER_ONLY */
+
+void cpu_interrupt(CPUState *cpu, int mask);
+
+#endif /* USER_ONLY */
+
+/**
+ * cpu_reset_interrupt:
+ * @cpu: The CPU to clear the interrupt on.
+ * @mask: The interrupt mask to clear.
+ *
+ * Resets interrupts on the vCPU @cpu.
+ */
+void cpu_reset_interrupt(CPUState *cpu, int mask);
+
 
 #endif
diff --git a/include/tpm/tpm.h b/include/tpm/tpm.h
new file mode 100644
index 0000000000..cc8f20e69e
--- /dev/null
+++ b/include/tpm/tpm.h
@@ -0,0 +1,21 @@
+/*
+ * Public TPM functions
+ *
+ * Copyright (C) 2011-2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@us.ibm.com>
+ *
+ * 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 QEMU_TPM_H
+#define QEMU_TPM_H
+
+#include "qemu/option.h"
+
+int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
+int tpm_init(void);
+void tpm_cleanup(void);
+
+#endif /* QEMU_TPM_H */
diff --git a/include/ui/console.h b/include/ui/console.h
index c42bca6efe..a37cf65602 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -450,9 +450,9 @@ void qemu_console_resize(DisplayState *ds, int width, int height);
 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
                        int dst_x, int dst_y, int w, int h);
 
-typedef CharDriverState *(VcHandler)(QemuOpts *);
+typedef CharDriverState *(VcHandler)(ChardevVC *vc);
 
-CharDriverState *vc_init(QemuOpts *opts);
+CharDriverState *vc_init(ChardevVC *vc);
 void register_vc_handler(VcHandler *handler);
 
 /* sdl.c */
diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
index 5a78fd764d..eba6d77d1d 100644
--- a/include/ui/qemu-spice.h
+++ b/include/ui/qemu-spice.h
@@ -44,10 +44,13 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
 void do_info_spice_print(Monitor *mon, const QObject *data);
 void do_info_spice(Monitor *mon, QObject **ret_data);
 
-CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
+CharDriverState *qemu_chr_open_spice_vmc(const char *type);
 #if SPICE_SERVER_VERSION >= 0x000c02
-CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts);
+CharDriverState *qemu_chr_open_spice_port(const char *name);
 void qemu_spice_register_ports(void);
+#else
+static inline CharDriverState *qemu_chr_open_spice_port(const char *name)
+{ return NULL; }
 #endif
 
 #else  /* CONFIG_SPICE */
diff --git a/kvm-all.c b/kvm-all.c
index 4decfdccd3..9b433d3163 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -826,11 +826,9 @@ static MemoryListener kvm_io_listener = {
     .priority = 10,
 };
 
-static void kvm_handle_interrupt(CPUArchState *env, int mask)
+static void kvm_handle_interrupt(CPUState *cpu, int mask)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
-
-    env->interrupt_request |= mask;
+    cpu->interrupt_request |= mask;
 
     if (!qemu_cpu_is_self(cpu)) {
         qemu_cpu_kick(cpu);
diff --git a/linux-user/main.c b/linux-user/main.c
index d8b0cd65fa..4e92a0b4c5 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3406,27 +3406,35 @@ static void usage(void)
            "Options and associated environment variables:\n"
            "\n");
 
-    maxarglen = maxenvlen = 0;
+    /* Calculate column widths. We must always have at least enough space
+     * for the column header.
+     */
+    maxarglen = strlen("Argument");
+    maxenvlen = strlen("Env-variable");
 
     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        int arglen = strlen(arginfo->argv);
+        if (arginfo->has_arg) {
+            arglen += strlen(arginfo->example) + 1;
+        }
         if (strlen(arginfo->env) > maxenvlen) {
             maxenvlen = strlen(arginfo->env);
         }
-        if (strlen(arginfo->argv) > maxarglen) {
-            maxarglen = strlen(arginfo->argv);
+        if (arglen > maxarglen) {
+            maxarglen = arglen;
         }
     }
 
-    printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
-            maxenvlen+1, "Env-variable");
+    printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
+            maxenvlen, "Env-variable");
 
     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
         if (arginfo->has_arg) {
             printf("-%s %-*s %-*s %s\n", arginfo->argv,
-                    (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
-                    maxenvlen, arginfo->env, arginfo->help);
+                   (int)(maxarglen - strlen(arginfo->argv) - 1),
+                   arginfo->example, maxenvlen, arginfo->env, arginfo->help);
         } else {
-            printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
+            printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
                     maxenvlen, arginfo->env,
                     arginfo->help);
         }
diff --git a/linux-user/socket.h b/linux-user/socket.h
index 93d47823d8..339cae5a16 100644
--- a/linux-user/socket.h
+++ b/linux-user/socket.h
@@ -87,6 +87,75 @@
 
 	#define TARGET_SOCK_MAX (SOCK_PACKET + 1)
 
+#elif defined(TARGET_ALPHA)
+
+    /* For setsockopt(2) */
+    #define TARGET_SOL_SOCKET   0xffff
+
+    #define TARGET_SO_DEBUG 0x0001
+    #define TARGET_SO_REUSEADDR 0x0004
+    #define TARGET_SO_KEEPALIVE 0x0008
+    #define TARGET_SO_DONTROUTE 0x0010
+    #define TARGET_SO_BROADCAST 0x0020
+    #define TARGET_SO_LINGER    0x0080
+    #define TARGET_SO_OOBINLINE 0x0100
+    /* To add :#define TARGET_SO_REUSEPORT 0x0200 */
+
+    #define TARGET_SO_TYPE      0x1008
+    #define TARGET_SO_ERROR 0x1007
+    #define TARGET_SO_SNDBUF    0x1001
+    #define TARGET_SO_RCVBUF    0x1002
+    #define TARGET_SO_SNDBUFFORCE   0x100a
+    #define TARGET_SO_RCVBUFFORCE   0x100b
+    #define TARGET_SO_RCVLOWAT  0x1010
+    #define TARGET_SO_SNDLOWAT  0x1011
+    #define TARGET_SO_RCVTIMEO  0x1012
+    #define TARGET_SO_SNDTIMEO  0x1013
+    #define TARGET_SO_ACCEPTCONN    0x1014
+    #define TARGET_SO_PROTOCOL  0x1028
+    #define TARGET_SO_DOMAIN    0x1029
+
+    /* linux-specific, might as well be the same as on i386 */
+    #define TARGET_SO_NO_CHECK  11
+    #define TARGET_SO_PRIORITY  12
+    #define TARGET_SO_BSDCOMPAT 14
+
+    #define TARGET_SO_PASSCRED  17
+    #define TARGET_SO_PEERCRED  18
+    #define TARGET_SO_BINDTODEVICE 25
+
+    /* Socket filtering */
+    #define TARGET_SO_ATTACH_FILTER        26
+    #define TARGET_SO_DETACH_FILTER        27
+
+    #define TARGET_SO_PEERNAME      28
+    #define TARGET_SO_TIMESTAMP     29
+    #define TARGET_SCM_TIMESTAMP        TARGET_SO_TIMESTAMP
+
+    #define TARGET_SO_PEERSEC       30
+    #define TARGET_SO_PASSSEC       34
+    #define TARGET_SO_TIMESTAMPNS       35
+    #define TARGET_SCM_TIMESTAMPNS      TARGET_SO_TIMESTAMPNS
+
+    /* Security levels - as per NRL IPv6 - don't actually do anything */
+    #define TARGET_SO_SECURITY_AUTHENTICATION       19
+    #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 20
+    #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK       21
+
+    #define TARGET_SO_MARK          36
+
+    #define TARGET_SO_TIMESTAMPING      37
+    #define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
+
+    #define TARGET_SO_RXQ_OVFL             40
+
+    #define TARGET_SO_WIFI_STATUS       41
+    #define TARGET_SCM_WIFI_STATUS      TARGET_SO_WIFI_STATUS
+    #define TARGET_SO_PEEK_OFF      42
+
+    /* Instruct lower device to use last 4-bytes of skb data as FCS */
+    #define TARGET_SO_NOFCS     43
+
 #else
 
 	/* For setsockopt(2) */
diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h
index 061711cc03..534e6e9963 100644
--- a/linux-user/sparc/syscall_nr.h
+++ b/linux-user/sparc/syscall_nr.h
@@ -200,6 +200,8 @@
 #define TARGET_NR__newselect         230 /* Linux Specific                              */
 #define TARGET_NR_time               231 /* Linux Specific                              */
 #define TARGET_NR_stime              233 /* Linux Specific                              */
+#define TARGET_NR_statfs64           234 /* Linux Specific                              */
+#define TARGET_NR_fstatfs64          235 /* Linux Specific                              */
 #define TARGET_NR__llseek            236 /* Linux Specific                              */
 #define TARGET_NR_mlock              237
 #define TARGET_NR_munlock            238
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 4e91a6eb9c..0fbae3c2f6 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -462,18 +462,6 @@ UNUSED static struct flags mmap_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags fcntl_flags[] = {
-    FLAG_TARGET(F_DUPFD),
-    FLAG_TARGET(F_GETFD),
-    FLAG_TARGET(F_SETFD),
-    FLAG_TARGET(F_GETFL),
-    FLAG_TARGET(F_SETFL),
-    FLAG_TARGET(F_GETLK),
-    FLAG_TARGET(F_SETLK),
-    FLAG_TARGET(F_SETLKW),
-    FLAG_END,
-};
-
 UNUSED static struct flags clone_flags[] = {
     FLAG_GENERIC(CLONE_VM),
     FLAG_GENERIC(CLONE_FS),
@@ -867,12 +855,85 @@ print_fcntl(const struct syscallname *name,
 {
     print_syscall_prologue(name);
     print_raw_param("%d", arg0, 0);
-    print_flags(fcntl_flags, arg1, 0);
-    /*
-     * TODO: check flags and print following argument only
-     *       when needed.
-     */
-    print_pointer(arg2, 1);
+    switch(arg1) {
+    case TARGET_F_DUPFD:
+        gemu_log("F_DUPFD,");
+        print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
+        break;
+    case TARGET_F_GETFD:
+        gemu_log("F_GETFD");
+        break;
+    case TARGET_F_SETFD:
+        gemu_log("F_SETFD,");
+        print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
+        break;
+    case TARGET_F_GETFL:
+        gemu_log("F_GETFL");
+        break;
+    case TARGET_F_SETFL:
+        gemu_log("F_SETFL,");
+        print_open_flags(arg2, 1);
+        break;
+    case TARGET_F_GETLK:
+        gemu_log("F_GETLK,");
+        print_pointer(arg2, 1);
+        break;
+    case TARGET_F_SETLK:
+        gemu_log("F_SETLK,");
+        print_pointer(arg2, 1);
+        break;
+    case TARGET_F_SETLKW:
+        gemu_log("F_SETLKW,");
+        print_pointer(arg2, 1);
+        break;
+    case TARGET_F_GETOWN:
+        gemu_log("F_GETOWN");
+        break;
+    case TARGET_F_SETOWN:
+        gemu_log("F_SETOWN,");
+        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+        break;
+    case TARGET_F_GETSIG:
+        gemu_log("F_GETSIG");
+        break;
+    case TARGET_F_SETSIG:
+        gemu_log("F_SETSIG,");
+        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+        break;
+#if TARGET_ABI_BITS == 32
+    case TARGET_F_GETLK64:
+        gemu_log("F_GETLK64,");
+        print_pointer(arg2, 1);
+        break;
+    case TARGET_F_SETLK64:
+        gemu_log("F_SETLK64,");
+        print_pointer(arg2, 1);
+        break;
+    case TARGET_F_SETLKW64:
+        gemu_log("F_SETLKW64,");
+        print_pointer(arg2, 1);
+        break;
+#endif
+    case TARGET_F_SETLEASE:
+        gemu_log("F_SETLEASE,");
+        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+        break;
+    case TARGET_F_GETLEASE:
+        gemu_log("F_GETLEASE");
+        break;
+    case TARGET_F_DUPFD_CLOEXEC:
+        gemu_log("F_DUPFD_CLOEXEC,");
+        print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
+        break;
+    case TARGET_F_NOTIFY:
+        gemu_log("F_NOTIFY,");
+        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+        break;
+    default:
+        print_raw_param(TARGET_ABI_FMT_ld, arg1, 0);
+        print_pointer(arg2, 1);
+        break;
+    }
     print_syscall_epilogue(name);
 }
 #define print_fcntl64   print_fcntl
@@ -1437,6 +1498,12 @@ if( cmd == val ) { \
         cmd &= ~FUTEX_PRIVATE_FLAG;
     }
 #endif
+#ifdef FUTEX_CLOCK_REALTIME
+    if (cmd & FUTEX_CLOCK_REALTIME) {
+        gemu_log("FUTEX_CLOCK_REALTIME|");
+        cmd &= ~FUTEX_CLOCK_REALTIME;
+    }
+#endif
     print_op(FUTEX_WAIT)
     print_op(FUTEX_WAKE)
     print_op(FUTEX_FD)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 19630eaf20..ee82a2da4e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -78,6 +78,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #ifdef CONFIG_ATTR
 #include "qemu/xattr.h"
 #endif
+#ifdef CONFIG_SENDFILE
+#include <sys/sendfile.h>
+#endif
 
 #define termios host_termios
 #define winsize host_winsize
@@ -1776,7 +1779,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
         errno = 0;
         return NULL;
     }
-    if (count > IOV_MAX) {
+    if (count < 0 || count > IOV_MAX) {
         errno = EINVAL;
         return NULL;
     }
@@ -2001,16 +2004,30 @@ out2:
     return ret;
 }
 
-/* do_accept() Must return target values and target errnos. */
-static abi_long do_accept(int fd, abi_ulong target_addr,
-                          abi_ulong target_addrlen_addr)
+/* If we don't have a system accept4() then just call accept.
+ * The callsites to do_accept4() will ensure that they don't
+ * pass a non-zero flags argument in this config.
+ */
+#ifndef CONFIG_ACCEPT4
+static inline int accept4(int sockfd, struct sockaddr *addr,
+                          socklen_t *addrlen, int flags)
+{
+    assert(flags == 0);
+    return accept(sockfd, addr, addrlen);
+}
+#endif
+
+/* do_accept4() Must return target values and target errnos. */
+static abi_long do_accept4(int fd, abi_ulong target_addr,
+                           abi_ulong target_addrlen_addr, int flags)
 {
     socklen_t addrlen;
     void *addr;
     abi_long ret;
 
-    if (target_addr == 0)
-       return get_errno(accept(fd, NULL, NULL));
+    if (target_addr == 0) {
+        return get_errno(accept4(fd, NULL, NULL, flags));
+    }
 
     /* linux returns EINVAL if addrlen pointer is invalid */
     if (get_user_u32(addrlen, target_addrlen_addr))
@@ -2025,7 +2042,7 @@ static abi_long do_accept(int fd, abi_ulong target_addr,
 
     addr = alloca(addrlen);
 
-    ret = get_errno(accept(fd, addr, &addrlen));
+    ret = get_errno(accept4(fd, addr, &addrlen, flags));
     if (!is_error(ret)) {
         host_to_target_sockaddr(target_addr, addr, addrlen);
         if (put_user_u32(addrlen, target_addrlen_addr))
@@ -2251,7 +2268,7 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
                 || get_user_ual(target_addrlen, vptr + 2 * n))
                 return -TARGET_EFAULT;
 
-            ret = do_accept(sockfd, target_addr, target_addrlen);
+            ret = do_accept4(sockfd, target_addr, target_addrlen, 0);
         }
         break;
     case SOCKOP_getsockname:
@@ -4922,6 +4939,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
 #endif
     switch (base_op) {
     case FUTEX_WAIT:
+    case FUTEX_WAIT_BITSET:
         if (timeout) {
             pts = &ts;
             target_to_host_timespec(pts, timeout);
@@ -4929,7 +4947,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
             pts = NULL;
         }
         return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
-                         pts, NULL, 0));
+                         pts, NULL, val3));
     case FUTEX_WAKE:
         return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
     case FUTEX_FD:
@@ -6673,7 +6691,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_accept
     case TARGET_NR_accept:
-        ret = do_accept(arg1, arg2, arg3);
+        ret = do_accept4(arg1, arg2, arg3, 0);
+        break;
+#endif
+#ifdef TARGET_NR_accept4
+    case TARGET_NR_accept4:
+#ifdef CONFIG_ACCEPT4
+        ret = do_accept4(arg1, arg2, arg3, arg4);
+#else
+        goto unimplemented;
+#endif
         break;
 #endif
 #ifdef TARGET_NR_bind
@@ -7530,8 +7557,58 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #else
         goto unimplemented;
 #endif
+
+#ifdef CONFIG_SENDFILE
+    case TARGET_NR_sendfile:
+    {
+        off_t *offp = NULL;
+        off_t off;
+        if (arg3) {
+            ret = get_user_sal(off, arg3);
+            if (is_error(ret)) {
+                break;
+            }
+            offp = &off;
+        }
+        ret = get_errno(sendfile(arg1, arg2, offp, arg4));
+        if (!is_error(ret) && arg3) {
+            abi_long ret2 = put_user_sal(off, arg3);
+            if (is_error(ret2)) {
+                ret = ret2;
+            }
+        }
+        break;
+    }
+#ifdef TARGET_NR_sendfile64
+    case TARGET_NR_sendfile64:
+    {
+        off_t *offp = NULL;
+        off_t off;
+        if (arg3) {
+            ret = get_user_s64(off, arg3);
+            if (is_error(ret)) {
+                break;
+            }
+            offp = &off;
+        }
+        ret = get_errno(sendfile(arg1, arg2, offp, arg4));
+        if (!is_error(ret) && arg3) {
+            abi_long ret2 = put_user_s64(off, arg3);
+            if (is_error(ret2)) {
+                ret = ret2;
+            }
+        }
+        break;
+    }
+#endif
+#else
     case TARGET_NR_sendfile:
+#ifdef TARGET_NR_sendfile64:
+    case TARGET_NR_sendfile64:
+#endif
         goto unimplemented;
+#endif
+
 #ifdef TARGET_NR_getpmsg
     case TARGET_NR_getpmsg:
         goto unimplemented;
@@ -7679,18 +7756,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         {
             int gidsetsize = arg1;
             target_id *target_grouplist;
-            gid_t *grouplist;
+            gid_t *grouplist = NULL;
             int i;
-
-            grouplist = alloca(gidsetsize * sizeof(gid_t));
-            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
-            if (!target_grouplist) {
-                ret = -TARGET_EFAULT;
-                goto fail;
+            if (gidsetsize) {
+                grouplist = alloca(gidsetsize * sizeof(gid_t));
+                target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
+                if (!target_grouplist) {
+                    ret = -TARGET_EFAULT;
+                    goto fail;
+                }
+                for (i = 0; i < gidsetsize; i++) {
+                    grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
+                }
+                unlock_user(target_grouplist, arg2, 0);
             }
-            for(i = 0;i < gidsetsize; i++)
-                grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
-            unlock_user(target_grouplist, arg2, 0);
             ret = get_errno(setgroups(gidsetsize, grouplist));
         }
         break;
@@ -8552,7 +8631,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
 #ifdef TARGET_NR_set_robust_list
     case TARGET_NR_set_robust_list:
-	goto unimplemented_nowarn;
+    case TARGET_NR_get_robust_list:
+        /* The ABI for supporting robust futexes has userspace pass
+         * the kernel a pointer to a linked list which is updated by
+         * userspace after the syscall; the list is walked by the kernel
+         * when the thread exits. Since the linked list in QEMU guest
+         * memory isn't a valid linked list for the host and we have
+         * no way to reliably intercept the thread-death event, we can't
+         * support these. Silently return ENOSYS so that guest userspace
+         * falls back to a non-robust futex implementation (which should
+         * be OK except in the corner case of the guest crashing while
+         * holding a mutex that is shared with another process via
+         * shared memory).
+         */
+        goto unimplemented_nowarn;
 #endif
 
 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
diff --git a/monitor.c b/monitor.c
index c48530bd55..112e92064d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -47,6 +47,7 @@
 #include "migration/migration.h"
 #include "sysemu/kvm.h"
 #include "qemu/acl.h"
+#include "tpm/tpm.h"
 #include "qapi/qmp/qint.h"
 #include "qapi/qmp/qfloat.h"
 #include "qapi/qmp/qlist.h"
@@ -855,17 +856,14 @@ EventInfoList *qmp_query_events(Error **errp)
 /* set the current CPU defined by the user */
 int monitor_set_cpu(int cpu_index)
 {
-    CPUArchState *env;
     CPUState *cpu;
 
-    for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        cpu = ENV_GET_CPU(env);
-        if (cpu->cpu_index == cpu_index) {
-            cur_mon->mon_cpu = env;
-            return 0;
-        }
+    cpu = qemu_get_cpu(cpu_index);
+    if (cpu == NULL) {
+        return -1;
     }
-    return -1;
+    cur_mon->mon_cpu = cpu->env_ptr;
+    return 0;
 }
 
 static CPUArchState *mon_get_cpu(void)
@@ -2722,6 +2720,13 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.cmd = do_trace_print_events,
     },
     {
+        .name       = "tpm",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the TPM device",
+        .mhandler.cmd = hmp_info_tpm,
+    },
+    {
         .name       = NULL,
     },
 };
diff --git a/qapi-schema.json b/qapi-schema.json
index 28b070f16b..fdaa9da133 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3153,7 +3153,7 @@
 ##
 # @ChardevHostdev:
 #
-# Configuration info for device chardevs.
+# Configuration info for device and pipe chardevs.
 #
 # @device: The name of the special file for the device,
 #          i.e. /dev/ttyS0 on Unix or COM1: on Windows
@@ -3166,7 +3166,7 @@
 ##
 # @ChardevSocket:
 #
-# Configuration info for socket chardevs.
+# Configuration info for (stream) socket chardevs.
 #
 # @addr: socket address to listen on (server=true)
 #        or connect to (server=false)
@@ -3185,6 +3185,93 @@
                                      '*telnet'  : 'bool' } }
 
 ##
+# @ChardevDgram:
+#
+# Configuration info for datagram socket chardevs.
+#
+# @remote: remote address
+# @local: #optional local address
+#
+# Since: 1.5
+##
+{ 'type': 'ChardevDgram', 'data': { 'remote' : 'SocketAddress',
+                                    '*local' : 'SocketAddress' } }
+
+##
+# @ChardevMux:
+#
+# Configuration info for mux chardevs.
+#
+# @chardev: name of the base chardev.
+#
+# Since: 1.5
+##
+{ 'type': 'ChardevMux', 'data': { 'chardev' : 'str' } }
+
+##
+# @ChardevStdio:
+#
+# Configuration info for stdio chardevs.
+#
+# @signal: #optional Allow signals (such as SIGINT triggered by ^C)
+#          be delivered to qemu.  Default: true in -nographic mode,
+#          false otherwise.
+#
+# Since: 1.5
+##
+{ 'type': 'ChardevStdio', 'data': { '*signal' : 'bool' } }
+
+##
+# @ChardevSpiceChannel:
+#
+# Configuration info for spice vm channel chardevs.
+#
+# @type: kind of channel (for example vdagent).
+#
+# Since: 1.5
+##
+{ 'type': 'ChardevSpiceChannel', 'data': { 'type'  : 'str' } }
+
+##
+# @ChardevSpicePort:
+#
+# Configuration info for spice port chardevs.
+#
+# @fqdn: name of the channel (see docs/spice-port-fqdn.txt)
+#
+# Since: 1.5
+##
+{ 'type': 'ChardevSpicePort', 'data': { 'fqdn'  : 'str' } }
+
+##
+# @ChardevVC:
+#
+# Configuration info for virtual console chardevs.
+#
+# @width:  console width,  in pixels
+# @height: console height, in pixels
+# @cols:   console width,  in chars
+# @rows:   console height, in chars
+#
+# Since: 1.5
+##
+{ 'type': 'ChardevVC', 'data': { '*width'  : 'int',
+                                 '*height' : 'int',
+                                 '*cols'   : 'int',
+                                 '*rows'   : 'int' } }
+
+##
+# @ChardevRingbuf:
+#
+# Configuration info for memory chardevs
+#
+# @size: #optional Ringbuffer size, must be power of two, default is 65536
+#
+# Since: 1.5
+##
+{ 'type': 'ChardevRingbuf', 'data': { '*size'  : 'int' } }
+
+##
 # @ChardevBackend:
 #
 # Configuration info for the new chardev backend.
@@ -3196,9 +3283,20 @@
 { 'union': 'ChardevBackend', 'data': { 'file'   : 'ChardevFile',
                                        'serial' : 'ChardevHostdev',
                                        'parallel': 'ChardevHostdev',
+                                       'pipe'   : 'ChardevHostdev',
                                        'socket' : 'ChardevSocket',
+                                       'dgram'  : 'ChardevDgram',
                                        'pty'    : 'ChardevDummy',
-                                       'null'   : 'ChardevDummy' } }
+                                       'null'   : 'ChardevDummy',
+                                       'mux'    : 'ChardevMux',
+                                       'msmouse': 'ChardevDummy',
+                                       'braille': 'ChardevDummy',
+                                       'stdio'  : 'ChardevStdio',
+                                       'console': 'ChardevDummy',
+                                       'spicevmc' : 'ChardevSpiceChannel',
+                                       'spiceport' : 'ChardevSpicePort',
+                                       'vc'     : 'ChardevVC',
+                                       'memory' : 'ChardevRingbuf' } }
 
 ##
 # @ChardevReturn:
@@ -3240,3 +3338,107 @@
 # Since: 1.4
 ##
 { 'command': 'chardev-remove', 'data': {'id': 'str'} }
+
+##
+# @TpmModel:
+#
+# An enumeration of TPM models
+#
+# @tpm-tis: TPM TIS model
+#
+# Since: 1.5
+##
+{ 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] }
+
+##
+# @query-tpm-models:
+#
+# Return a list of supported TPM models
+#
+# Returns: a list of TpmModel
+#
+# Since: 1.5
+##
+{ 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
+
+##
+# @TpmType:
+#
+# An enumeration of TPM types
+#
+# @passthrough: TPM passthrough type
+#
+# Since: 1.5
+##
+{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
+
+##
+# @query-tpm-types:
+#
+# Return a list of supported TPM types
+#
+# Returns: a list of TpmType
+#
+# Since: 1.5
+##
+{ 'command': 'query-tpm-types', 'returns': ['TpmType'] }
+
+##
+# @TPMPassthroughOptions:
+#
+# Information about the TPM passthrough type
+#
+# @path: #optional string describing the path used for accessing the TPM device
+#
+# @cancel-path: #optional string showing the TPM's sysfs cancel file
+#               for cancellation of TPM commands while they are executing
+#
+# Since: 1.5
+##
+{ 'type': 'TPMPassthroughOptions', 'data': { '*path' : 'str',
+                                             '*cancel-path' : 'str'} }
+
+##
+# @TpmTypeOptions:
+#
+# A union referencing different TPM backend types' configuration options
+#
+# @tpm-passthough-options: TPMPassthroughOptions describing the TPM
+#                          passthrough configuration options
+#
+# Since: 1.5
+##
+{ 'union': 'TpmTypeOptions',
+   'data': { 'tpm-passthrough-options' : 'TPMPassthroughOptions' } }
+
+##
+# @TpmInfo:
+#
+# Information about the TPM
+#
+# @id: The Id of the TPM
+#
+# @model: The TPM frontend model
+#
+# @type: The TPM (backend) type being used
+#
+# @tpm-options: The TPM (backend) type configuration options
+#
+# Since: 1.5
+##
+{ 'type': 'TPMInfo',
+  'data': {'id': 'str',
+           'model': 'TpmModel',
+           'type': 'TpmType',
+           'tpm-options': 'TpmTypeOptions' } }
+
+##
+# @query-tpm:
+#
+# Return information about the TPM device
+#
+# Returns: @TPMInfo on success
+#
+# Since: 1.5
+##
+{ 'command': 'query-tpm', 'returns': ['TPMInfo'] }
diff --git a/qemu-char.c b/qemu-char.c
index 04aa589c7e..e6337971a5 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -217,7 +217,7 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_null(void)
 {
     CharDriverState *chr;
 
@@ -533,6 +533,30 @@ int send_all(int fd, const void *_buf, int len1)
     }
     return len1 - len;
 }
+
+int recv_all(int fd, void *_buf, int len1, bool single_read)
+{
+    int ret, len;
+    uint8_t *buf = _buf;
+
+    len = len1;
+    while ((len > 0) && (ret = read(fd, buf, len)) != 0) {
+        if (ret < 0) {
+            if (errno != EINTR && errno != EAGAIN) {
+                return -1;
+            }
+            continue;
+        } else {
+            if (single_read) {
+                return ret;
+            }
+            buf += ret;
+            len -= ret;
+        }
+    }
+    return len1 - len;
+}
+
 #endif /* !_WIN32 */
 
 typedef struct IOWatchPoll
@@ -817,23 +841,11 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
-{
-    int fd_out;
-
-    TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
-                      O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
-    if (fd_out < 0) {
-        return NULL;
-    }
-    return qemu_chr_open_fd(-1, fd_out);
-}
-
-static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts)
 {
     int fd_in, fd_out;
     char filename_in[256], filename_out[256];
-    const char *filename = qemu_opt_get(opts, "path");
+    const char *filename = opts->device;
 
     if (filename == NULL) {
         fprintf(stderr, "chardev: pipe: no filename given\n");
@@ -896,7 +908,7 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr)
     fd_chr_close(chr);
 }
 
-static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts)
 {
     CharDriverState *chr;
 
@@ -912,8 +924,10 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
     chr = qemu_chr_open_fd(0, 1);
     chr->chr_close = qemu_chr_close_stdio;
     chr->chr_set_echo = qemu_chr_set_echo_stdio;
-    stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
-                                           display_type != DT_NOGRAPHIC);
+    stdio_allow_signal = display_type != DT_NOGRAPHIC;
+    if (opts->has_signal) {
+        stdio_allow_signal = opts->signal;
+    }
     qemu_chr_fe_set_echo(chr, false);
 
     return chr;
@@ -1143,13 +1157,13 @@ static void pty_chr_close(struct CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_pty(const char *id,
+                                          ChardevReturn *ret)
 {
     CharDriverState *chr;
     PtyCharDriver *s;
     struct termios tty;
-    const char *label;
-    int master_fd, slave_fd, len;
+    int master_fd, slave_fd;
 #if defined(__OpenBSD__) || defined(__DragonFly__)
     char pty_name[PATH_MAX];
 #define q_ptsname(x) pty_name
@@ -1170,17 +1184,12 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
 
     chr = g_malloc0(sizeof(CharDriverState));
 
-    len = strlen(q_ptsname(master_fd)) + 5;
-    chr->filename = g_malloc(len);
-    snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd));
-    qemu_opt_set(opts, "path", q_ptsname(master_fd));
+    chr->filename = g_strdup_printf("pty:%s", q_ptsname(master_fd));
+    ret->pty = g_strdup(q_ptsname(master_fd));
+    ret->has_pty = true;
 
-    label = qemu_opts_id(opts);
-    fprintf(stderr, "char device redirected to %s%s%s%s\n",
-            q_ptsname(master_fd),
-            label ? " (label " : "",
-            label ? label      : "",
-            label ? ")"        : "");
+    fprintf(stderr, "char device redirected to %s (label %s)\n",
+            q_ptsname(master_fd), id);
 
     s = g_malloc0(sizeof(PtyCharDriver));
     chr->opaque = s;
@@ -1405,18 +1414,6 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd)
     chr->chr_close = qemu_chr_close_tty;
     return chr;
 }
-
-static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
-{
-    const char *filename = qemu_opt_get(opts, "path");
-    int fd;
-
-    TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK));
-    if (fd < 0) {
-        return NULL;
-    }
-    return qemu_chr_open_tty_fd(fd);
-}
 #endif /* __linux__ || __sun__ */
 
 #if defined(__linux__)
@@ -1841,11 +1838,6 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename)
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
-{
-    return qemu_chr_open_win_path(qemu_opt_get(opts, "path"));
-}
-
 static int win_chr_pipe_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -1925,9 +1917,9 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 }
 
 
-static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts)
 {
-    const char *filename = qemu_opt_get(opts, "path");
+    const char *filename = opts->device;
     CharDriverState *chr;
     WinCharState *s;
 
@@ -1960,25 +1952,11 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_win_con(void)
 {
     return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
 }
 
-static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
-{
-    const char *file_out = qemu_opt_get(opts, "path");
-    HANDLE fd_out;
-
-    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
-                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (fd_out == INVALID_HANDLE_VALUE) {
-        return NULL;
-    }
-
-    return qemu_chr_open_win_file(fd_out);
-}
-
 static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -2116,7 +2094,7 @@ static void win_stdio_close(CharDriverState *chr)
     g_free(chr);
 }
 
-static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts)
 {
     CharDriverState   *chr;
     WinStdioCharState *stdio;
@@ -2283,21 +2261,14 @@ static void udp_chr_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_udp_fd(int fd)
 {
     CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;
-    Error *local_err = NULL;
-    int fd = -1;
 
     chr = g_malloc0(sizeof(CharDriverState));
     s = g_malloc0(sizeof(NetCharDriver));
 
-    fd = inet_dgram_opts(opts, &local_err);
-    if (fd < 0) {
-        goto return_err;
-    }
-
     s->fd = fd;
     s->chan = io_channel_from_socket(s->fd);
     s->bufcnt = 0;
@@ -2307,18 +2278,18 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
     chr->chr_update_read_handler = udp_chr_update_read_handler;
     chr->chr_close = udp_chr_close;
     return chr;
+}
 
-return_err:
-    if (local_err) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-    }
-    g_free(chr);
-    g_free(s);
-    if (fd >= 0) {
-        closesocket(fd);
+static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
+{
+    Error *local_err = NULL;
+    int fd = -1;
+
+    fd = inet_dgram_opts(opts, &local_err);
+    if (fd < 0) {
+        return NULL;
     }
-    return NULL;
+    return qemu_chr_open_udp_fd(fd);
 }
 
 /***********************************************************/
@@ -2685,7 +2656,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
         s->do_nodelay = do_nodelay;
         getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host),
                     serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
-        snprintf(chr->filename, 256, "%s:%s:%s%s%s%s",
+        snprintf(chr->filename, 256, "%s:%s%s%s:%s%s",
                  is_telnet ? "telnet" : "tcp",
                  left, host, right, serv,
                  is_listen ? ",server" : "");
@@ -2906,7 +2877,8 @@ static void ringbuf_chr_close(struct CharDriverState *chr)
     chr->opaque = NULL;
 }
 
-static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts,
+                                              Error **errp)
 {
     CharDriverState *chr;
     RingBufCharDriver *d;
@@ -2914,14 +2886,11 @@ static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts)
     chr = g_malloc0(sizeof(CharDriverState));
     d = g_malloc(sizeof(*d));
 
-    d->size = qemu_opt_get_size(opts, "size", 0);
-    if (d->size == 0) {
-        d->size = 65536;
-    }
+    d->size = opts->has_size ? opts->size : 65536;
 
     /* The size must be power of 2 */
     if (d->size & (d->size - 1)) {
-        error_report("size of ringbuf device must be power of two");
+        error_setg(errp, "size of ringbuf chardev must be power of two");
         goto fail;
     }
 
@@ -3162,25 +3131,88 @@ fail:
     return NULL;
 }
 
-#ifdef HAVE_CHARDEV_PARPORT
+static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend,
+                                    Error **errp)
+{
+    const char *path = qemu_opt_get(opts, "path");
+
+    if (path == NULL) {
+        error_setg(errp, "chardev: file: no filename given");
+        return;
+    }
+    backend->file = g_new0(ChardevFile, 1);
+    backend->file->out = g_strdup(path);
+}
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
+                                 Error **errp)
 {
-    const char *filename = qemu_opt_get(opts, "path");
-    int fd;
+    backend->stdio = g_new0(ChardevStdio, 1);
+    backend->stdio->has_signal = true;
+    backend->stdio->signal =
+        qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC);
+}
 
-    fd = qemu_open(filename, O_RDWR);
-    if (fd < 0) {
-        return NULL;
+static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
+                                  Error **errp)
+{
+    const char *device = qemu_opt_get(opts, "path");
+
+    if (device == NULL) {
+        error_setg(errp, "chardev: serial/tty: no device path given");
+        return;
     }
-    return qemu_chr_open_pp_fd(fd);
+    backend->serial = g_new0(ChardevHostdev, 1);
+    backend->serial->device = g_strdup(device);
 }
 
-#endif
+static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
+                                    Error **errp)
+{
+    const char *device = qemu_opt_get(opts, "path");
+
+    if (device == NULL) {
+        error_setg(errp, "chardev: parallel: no device path given");
+        return;
+    }
+    backend->parallel = g_new0(ChardevHostdev, 1);
+    backend->parallel->device = g_strdup(device);
+}
+
+static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
+                                Error **errp)
+{
+    const char *device = qemu_opt_get(opts, "path");
+
+    if (device == NULL) {
+        error_setg(errp, "chardev: pipe: no device path given");
+        return;
+    }
+    backend->pipe = g_new0(ChardevHostdev, 1);
+    backend->pipe->device = g_strdup(device);
+}
+
+static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
+                                   Error **errp)
+{
+    int val;
+
+    backend->memory = g_new0(ChardevRingbuf, 1);
+
+    val = qemu_opt_get_number(opts, "size", 0);
+    if (val != 0) {
+        backend->memory->has_size = true;
+        backend->memory->size = val;
+    }
+}
 
 typedef struct CharDriver {
     const char *name;
+    /* old, pre qapi */
     CharDriverState *(*open)(QemuOpts *opts);
+    /* new, qapi-based */
+    int kind;
+    void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
 } CharDriver;
 
 static GSList *backends;
@@ -3196,6 +3228,19 @@ void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *)
     backends = g_slist_append(backends, s);
 }
 
+void register_char_driver_qapi(const char *name, int kind,
+        void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp))
+{
+    CharDriver *s;
+
+    s = g_malloc0(sizeof(*s));
+    s->name = g_strdup(name);
+    s->kind = kind;
+    s->parse = parse;
+
+    backends = g_slist_append(backends, s);
+}
+
 CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
                                     void (*init)(struct CharDriverState *s),
                                     Error **errp)
@@ -3227,6 +3272,51 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         return NULL;
     }
 
+    if (!cd->open) {
+        /* using new, qapi init */
+        ChardevBackend *backend = g_new0(ChardevBackend, 1);
+        ChardevReturn *ret = NULL;
+        const char *id = qemu_opts_id(opts);
+        const char *bid = NULL;
+
+        if (qemu_opt_get_bool(opts, "mux", 0)) {
+            bid = g_strdup_printf("%s-base", id);
+        }
+
+        chr = NULL;
+        backend->kind = cd->kind;
+        if (cd->parse) {
+            cd->parse(opts, backend, errp);
+            if (error_is_set(errp)) {
+                goto qapi_out;
+            }
+        }
+        ret = qmp_chardev_add(bid ? bid : id, backend, errp);
+        if (error_is_set(errp)) {
+            goto qapi_out;
+        }
+
+        if (bid) {
+            qapi_free_ChardevBackend(backend);
+            qapi_free_ChardevReturn(ret);
+            backend = g_new0(ChardevBackend, 1);
+            backend->mux = g_new0(ChardevMux, 1);
+            backend->kind = CHARDEV_BACKEND_KIND_MUX;
+            backend->mux->chardev = g_strdup(bid);
+            ret = qmp_chardev_add(id, backend, errp);
+            if (error_is_set(errp)) {
+                goto qapi_out;
+            }
+        }
+
+        chr = qemu_chr_find(id);
+
+    qapi_out:
+        qapi_free_ChardevBackend(backend);
+        qapi_free_ChardevReturn(ret);
+        return chr;
+    }
+
     chr = cd->open(opts);
     if (!chr) {
         error_setg(errp, "chardev: opening backend \"%s\" failed",
@@ -3582,11 +3672,23 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock,
                                    is_telnet, is_waitconnect, errp);
 }
 
+static CharDriverState *qmp_chardev_open_dgram(ChardevDgram *dgram,
+                                               Error **errp)
+{
+    int fd;
+
+    fd = socket_dgram(dgram->remote, dgram->local, errp);
+    if (error_is_set(errp)) {
+        return NULL;
+    }
+    return qemu_chr_open_udp_fd(fd);
+}
+
 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                                Error **errp)
 {
     ChardevReturn *ret = g_new0(ChardevReturn, 1);
-    CharDriverState *chr = NULL;
+    CharDriverState *base, *chr = NULL;
 
     chr = qemu_chr_find(id);
     if (chr) {
@@ -3605,24 +3707,61 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     case CHARDEV_BACKEND_KIND_PARALLEL:
         chr = qmp_chardev_open_parallel(backend->parallel, errp);
         break;
+    case CHARDEV_BACKEND_KIND_PIPE:
+        chr = qemu_chr_open_pipe(backend->pipe);
+        break;
     case CHARDEV_BACKEND_KIND_SOCKET:
         chr = qmp_chardev_open_socket(backend->socket, errp);
         break;
+    case CHARDEV_BACKEND_KIND_DGRAM:
+        chr = qmp_chardev_open_dgram(backend->dgram, errp);
+        break;
 #ifdef HAVE_CHARDEV_TTY
     case CHARDEV_BACKEND_KIND_PTY:
-    {
-        /* qemu_chr_open_pty sets "path" in opts */
-        QemuOpts *opts;
-        opts = qemu_opts_create_nofail(qemu_find_opts("chardev"));
-        chr = qemu_chr_open_pty(opts);
-        ret->pty = g_strdup(qemu_opt_get(opts, "path"));
-        ret->has_pty = true;
-        qemu_opts_del(opts);
+        chr = qemu_chr_open_pty(id, ret);
         break;
-    }
 #endif
     case CHARDEV_BACKEND_KIND_NULL:
-        chr = qemu_chr_open_null(NULL);
+        chr = qemu_chr_open_null();
+        break;
+    case CHARDEV_BACKEND_KIND_MUX:
+        base = qemu_chr_find(backend->mux->chardev);
+        if (base == NULL) {
+            error_setg(errp, "mux: base chardev %s not found",
+                       backend->mux->chardev);
+            break;
+        }
+        chr = qemu_chr_open_mux(base);
+        break;
+    case CHARDEV_BACKEND_KIND_MSMOUSE:
+        chr = qemu_chr_open_msmouse();
+        break;
+#ifdef CONFIG_BRLAPI
+    case CHARDEV_BACKEND_KIND_BRAILLE:
+        chr = chr_baum_init();
+        break;
+#endif
+    case CHARDEV_BACKEND_KIND_STDIO:
+        chr = qemu_chr_open_stdio(backend->stdio);
+        break;
+#ifdef _WIN32
+    case CHARDEV_BACKEND_KIND_CONSOLE:
+        chr = qemu_chr_open_win_con();
+        break;
+#endif
+#ifdef CONFIG_SPICE
+    case CHARDEV_BACKEND_KIND_SPICEVMC:
+        chr = qemu_chr_open_spice_vmc(backend->spicevmc->type);
+        break;
+    case CHARDEV_BACKEND_KIND_SPICEPORT:
+        chr = qemu_chr_open_spice_port(backend->spiceport->fqdn);
+        break;
+#endif
+    case CHARDEV_BACKEND_KIND_VC:
+        chr = vc_init(backend->vc);
+        break;
+    case CHARDEV_BACKEND_KIND_MEMORY:
+        chr = qemu_chr_open_ringbuf(backend->memory, errp);
         break;
     default:
         error_setg(errp, "unknown chardev backend (%d)", backend->kind);
@@ -3634,7 +3773,8 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     }
     if (chr) {
         chr->label = g_strdup(id);
-        chr->avail_connections = 1;
+        chr->avail_connections =
+            (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
         QTAILQ_INSERT_TAIL(&chardevs, chr, next);
         return ret;
     } else {
@@ -3662,30 +3802,27 @@ void qmp_chardev_remove(const char *id, Error **errp)
 
 static void register_types(void)
 {
-    register_char_driver("null", qemu_chr_open_null);
+    register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL);
     register_char_driver("socket", qemu_chr_open_socket);
     register_char_driver("udp", qemu_chr_open_udp);
-    register_char_driver("memory", qemu_chr_open_ringbuf);
-#ifdef _WIN32
-    register_char_driver("file", qemu_chr_open_win_file_out);
-    register_char_driver("pipe", qemu_chr_open_win_pipe);
-    register_char_driver("console", qemu_chr_open_win_con);
-    register_char_driver("serial", qemu_chr_open_win);
-    register_char_driver("stdio", qemu_chr_open_win_stdio);
-#else
-    register_char_driver("file", qemu_chr_open_file_out);
-    register_char_driver("pipe", qemu_chr_open_pipe);
-    register_char_driver("stdio", qemu_chr_open_stdio);
-#endif
-#ifdef HAVE_CHARDEV_TTY
-    register_char_driver("tty", qemu_chr_open_tty);
-    register_char_driver("serial", qemu_chr_open_tty);
-    register_char_driver("pty", qemu_chr_open_pty);
-#endif
-#ifdef HAVE_CHARDEV_PARPORT
-    register_char_driver("parallel", qemu_chr_open_pp);
-    register_char_driver("parport", qemu_chr_open_pp);
-#endif
+    register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY,
+                              qemu_chr_parse_ringbuf);
+    register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE,
+                              qemu_chr_parse_file_out);
+    register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO,
+                              qemu_chr_parse_stdio);
+    register_char_driver_qapi("serial", CHARDEV_BACKEND_KIND_SERIAL,
+                              qemu_chr_parse_serial);
+    register_char_driver_qapi("tty", CHARDEV_BACKEND_KIND_SERIAL,
+                              qemu_chr_parse_serial);
+    register_char_driver_qapi("parallel", CHARDEV_BACKEND_KIND_PARALLEL,
+                              qemu_chr_parse_parallel);
+    register_char_driver_qapi("parport", CHARDEV_BACKEND_KIND_PARALLEL,
+                              qemu_chr_parse_parallel);
+    register_char_driver_qapi("pty", CHARDEV_BACKEND_KIND_PTY, NULL);
+    register_char_driver_qapi("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL);
+    register_char_driver_qapi("pipe", CHARDEV_BACKEND_KIND_PIPE,
+                              qemu_chr_parse_pipe);
 }
 
 type_init(register_types);
diff --git a/qemu-options.hx b/qemu-options.hx
index cd76f2a00c..30fb85d619 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2217,6 +2217,80 @@ STEXI
 ETEXI
 DEFHEADING()
 
+#ifdef CONFIG_TPM
+DEFHEADING(TPM device options:)
+
+DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
+    "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
+    "                use path to provide path to a character device; default is /dev/tpm0\n"
+    "                use cancel-path to provide path to TPM's cancel sysfs entry; if\n"
+    "                not provided it will be searched for in /sys/class/misc/tpm?/device\n",
+    QEMU_ARCH_ALL)
+STEXI
+
+The general form of a TPM device option is:
+@table @option
+
+@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
+@findex -tpmdev
+Backend type must be:
+@option{passthrough}.
+
+The specific backend type will determine the applicable options.
+The @code{-tpmdev} option requires a @code{-device} option.
+
+Options to each backend are described below.
+
+Use 'help' to print all available TPM backend types.
+@example
+qemu -tpmdev help
+@end example
+
+@item -tpmdev passthrough, id=@var{id}, path=@var{path}, cancel-path=@var{cancel-path}
+
+(Linux-host only) Enable access to the host's TPM using the passthrough
+driver.
+
+@option{path} specifies the path to the host's TPM device, i.e., on
+a Linux host this would be @code{/dev/tpm0}.
+@option{path} is optional and by default @code{/dev/tpm0} is used.
+
+@option{cancel-path} specifies the path to the host TPM device's sysfs
+entry allowing for cancellation of an ongoing TPM command.
+@option{cancel-path} is optional and by default QEMU will search for the
+sysfs entry to use.
+
+Some notes about using the host's TPM with the passthrough driver:
+
+The TPM device accessed by the passthrough driver must not be
+used by any other application on the host.
+
+Since the host's firmware (BIOS/UEFI) has already initialized the TPM,
+the VM's firmware (BIOS/UEFI) will not be able to initialize the
+TPM again and may therefore not show a TPM-specific menu that would
+otherwise allow the user to configure the TPM, e.g., allow the user to
+enable/disable or activate/deactivate the TPM.
+Further, if TPM ownership is released from within a VM then the host's TPM
+will get disabled and deactivated. To enable and activate the
+TPM again afterwards, the host has to be rebooted and the user is
+required to enter the firmware's menu to enable and activate the TPM.
+If the TPM is left disabled and/or deactivated most TPM commands will fail.
+
+To create a passthrough TPM use the following two options:
+@example
+-tpmdev passthrough,id=tpm0 -device tpm-tis,tpmdev=tpm0
+@end example
+Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
+@code{tpmdev=tpm0} in the device option.
+
+@end table
+
+ETEXI
+
+DEFHEADING()
+
+#endif
+
 DEFHEADING(Linux/Multiboot boot specific:)
 STEXI
 
diff --git a/qga/channel-win32.c b/qga/channel-win32.c
index 16bf44a376..7ed98d72fb 100644
--- a/qga/channel-win32.c
+++ b/qga/channel-win32.c
@@ -287,7 +287,7 @@ GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size)
 static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
                                 const gchar *path)
 {
-    if (!method == GA_CHANNEL_VIRTIO_SERIAL) {
+    if (method != GA_CHANNEL_VIRTIO_SERIAL) {
         g_critical("unsupported communication method");
         return false;
     }
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 7a0202eb2a..d7da850615 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -15,6 +15,10 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
 #include "qga/guest-agent-core.h"
 #include "qga-qmp-commands.h"
 #include "qapi/qmp/qerror.h"
@@ -119,6 +123,77 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
     /* succeded */
 }
 
+int64_t qmp_guest_get_time(Error **errp)
+{
+   int ret;
+   qemu_timeval tq;
+   int64_t time_ns;
+
+   ret = qemu_gettimeofday(&tq);
+   if (ret < 0) {
+       error_setg_errno(errp, errno, "Failed to get time");
+       return -1;
+   }
+
+   time_ns = tq.tv_sec * 1000000000LL + tq.tv_usec * 1000;
+   return time_ns;
+}
+
+void qmp_guest_set_time(int64_t time_ns, Error **errp)
+{
+    int ret;
+    int status;
+    pid_t pid;
+    Error *local_err = NULL;
+    struct timeval tv;
+
+    /* year-2038 will overflow in case time_t is 32bit */
+    if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
+        error_setg(errp, "Time %" PRId64 " is too large", time_ns);
+        return;
+    }
+
+    tv.tv_sec = time_ns / 1000000000;
+    tv.tv_usec = (time_ns % 1000000000) / 1000;
+
+    ret = settimeofday(&tv, NULL);
+    if (ret < 0) {
+        error_setg_errno(errp, errno, "Failed to set time to guest");
+        return;
+    }
+
+    /* Set the Hardware Clock to the current System Time. */
+    pid = fork();
+    if (pid == 0) {
+        setsid();
+        reopen_fd_to_null(0);
+        reopen_fd_to_null(1);
+        reopen_fd_to_null(2);
+
+        execle("/sbin/hwclock", "hwclock", "-w", NULL, environ);
+        _exit(EXIT_FAILURE);
+    } else if (pid < 0) {
+        error_setg_errno(errp, errno, "failed to create child process");
+        return;
+    }
+
+    ga_wait_child(pid, &status, &local_err);
+    if (error_is_set(&local_err)) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    if (!WIFEXITED(status)) {
+        error_setg(errp, "child process has terminated abnormally");
+        return;
+    }
+
+    if (WEXITSTATUS(status)) {
+        error_setg(errp, "hwclock failed to set hardware clock to system time");
+        return;
+    }
+}
+
 typedef struct GuestFileHandle {
     uint64_t id;
     FILE *fh;
@@ -129,14 +204,22 @@ static struct {
     QTAILQ_HEAD(, GuestFileHandle) filehandles;
 } guest_file_state;
 
-static void guest_file_handle_add(FILE *fh)
+static int64_t guest_file_handle_add(FILE *fh, Error **errp)
 {
     GuestFileHandle *gfh;
+    int64_t handle;
+
+    handle = ga_get_fd_handle(ga_state, errp);
+    if (error_is_set(errp)) {
+        return 0;
+    }
 
     gfh = g_malloc0(sizeof(GuestFileHandle));
-    gfh->id = fileno(fh);
+    gfh->id = handle;
     gfh->fh = fh;
     QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
+
+    return handle;
 }
 
 static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
@@ -158,7 +241,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
 {
     FILE *fh;
     int fd;
-    int64_t ret = -1;
+    int64_t ret = -1, handle;
 
     if (!has_mode) {
         mode = "r";
@@ -184,9 +267,14 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
         return -1;
     }
 
-    guest_file_handle_add(fh);
-    slog("guest-file-open, handle: %d", fd);
-    return fd;
+    handle = guest_file_handle_add(fh, err);
+    if (error_is_set(err)) {
+        fclose(fh);
+        return -1;
+    }
+
+    slog("guest-file-open, handle: %d", handle);
+    return handle;
 }
 
 void qmp_guest_file_close(int64_t handle, Error **err)
@@ -1027,6 +1115,162 @@ error:
     return NULL;
 }
 
+#define SYSCONF_EXACT(name, err) sysconf_exact((name), #name, (err))
+
+static long sysconf_exact(int name, const char *name_str, Error **err)
+{
+    long ret;
+
+    errno = 0;
+    ret = sysconf(name);
+    if (ret == -1) {
+        if (errno == 0) {
+            error_setg(err, "sysconf(%s): value indefinite", name_str);
+        } else {
+            error_setg_errno(err, errno, "sysconf(%s)", name_str);
+        }
+    }
+    return ret;
+}
+
+/* Transfer online/offline status between @vcpu and the guest system.
+ *
+ * On input either @errp or *@errp must be NULL.
+ *
+ * In system-to-@vcpu direction, the following @vcpu fields are accessed:
+ * - R: vcpu->logical_id
+ * - W: vcpu->online
+ * - W: vcpu->can_offline
+ *
+ * In @vcpu-to-system direction, the following @vcpu fields are accessed:
+ * - R: vcpu->logical_id
+ * - R: vcpu->online
+ *
+ * Written members remain unmodified on error.
+ */
+static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
+                          Error **errp)
+{
+    char *dirpath;
+    int dirfd;
+
+    dirpath = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
+                              vcpu->logical_id);
+    dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+    if (dirfd == -1) {
+        error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+    } else {
+        static const char fn[] = "online";
+        int fd;
+        int res;
+
+        fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
+        if (fd == -1) {
+            if (errno != ENOENT) {
+                error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
+            } else if (sys2vcpu) {
+                vcpu->online = true;
+                vcpu->can_offline = false;
+            } else if (!vcpu->online) {
+                error_setg(errp, "logical processor #%" PRId64 " can't be "
+                           "offlined", vcpu->logical_id);
+            } /* otherwise pretend successful re-onlining */
+        } else {
+            unsigned char status;
+
+            res = pread(fd, &status, 1, 0);
+            if (res == -1) {
+                error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
+            } else if (res == 0) {
+                error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
+                           fn);
+            } else if (sys2vcpu) {
+                vcpu->online = (status != '0');
+                vcpu->can_offline = true;
+            } else if (vcpu->online != (status != '0')) {
+                status = '0' + vcpu->online;
+                if (pwrite(fd, &status, 1, 0) == -1) {
+                    error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
+                                     fn);
+                }
+            } /* otherwise pretend successful re-(on|off)-lining */
+
+            res = close(fd);
+            g_assert(res == 0);
+        }
+
+        res = close(dirfd);
+        g_assert(res == 0);
+    }
+
+    g_free(dirpath);
+}
+
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+{
+    int64_t current;
+    GuestLogicalProcessorList *head, **link;
+    long sc_max;
+    Error *local_err = NULL;
+
+    current = 0;
+    head = NULL;
+    link = &head;
+    sc_max = SYSCONF_EXACT(_SC_NPROCESSORS_CONF, &local_err);
+
+    while (local_err == NULL && current < sc_max) {
+        GuestLogicalProcessor *vcpu;
+        GuestLogicalProcessorList *entry;
+
+        vcpu = g_malloc0(sizeof *vcpu);
+        vcpu->logical_id = current++;
+        vcpu->has_can_offline = true; /* lolspeak ftw */
+        transfer_vcpu(vcpu, true, &local_err);
+
+        entry = g_malloc0(sizeof *entry);
+        entry->value = vcpu;
+
+        *link = entry;
+        link = &entry->next;
+    }
+
+    if (local_err == NULL) {
+        /* there's no guest with zero VCPUs */
+        g_assert(head != NULL);
+        return head;
+    }
+
+    qapi_free_GuestLogicalProcessorList(head);
+    error_propagate(errp, local_err);
+    return NULL;
+}
+
+int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
+{
+    int64_t processed;
+    Error *local_err = NULL;
+
+    processed = 0;
+    while (vcpus != NULL) {
+        transfer_vcpu(vcpus->value, false, &local_err);
+        if (local_err != NULL) {
+            break;
+        }
+        ++processed;
+        vcpus = vcpus->next;
+    }
+
+    if (local_err != NULL) {
+        if (processed == 0) {
+            error_propagate(errp, local_err);
+        } else {
+            error_free(local_err);
+        }
+    }
+
+    return processed;
+}
+
 #else /* defined(__linux__) */
 
 void qmp_guest_suspend_disk(Error **err)
@@ -1050,6 +1294,18 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
     return NULL;
 }
 
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return NULL;
+}
+
+int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return -1;
+}
+
 #endif
 
 #if !defined(CONFIG_FSFREEZE)
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 7e8ecb3b40..b19be9db48 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -278,6 +278,29 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **err)
     return NULL;
 }
 
+int64_t qmp_guest_get_time(Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return -1;
+}
+
+void qmp_guest_set_time(int64_t time_ns, Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+}
+
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return NULL;
+}
+
+int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return -1;
+}
+
 /* register init/cleanup routines for stateful command groups */
 void ga_command_state_init(GAState *s, GACommandState *cs)
 {
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
index 3354598362..624a559d94 100644
--- a/qga/guest-agent-core.h
+++ b/qga/guest-agent-core.h
@@ -35,6 +35,7 @@ bool ga_is_frozen(GAState *s);
 void ga_set_frozen(GAState *s);
 void ga_unset_frozen(GAState *s);
 const char *ga_fsfreeze_hook(GAState *s);
+int64_t ga_get_fd_handle(GAState *s, Error **errp);
 
 #ifndef _WIN32
 void reopen_fd_to_null(int fd);
diff --git a/qga/main.c b/qga/main.c
index db281a508b..74ef7885b2 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -15,6 +15,7 @@
 #include <stdbool.h>
 #include <glib.h>
 #include <getopt.h>
+#include <glib/gstdio.h>
 #ifndef _WIN32
 #include <syslog.h>
 #include <sys/wait.h>
@@ -30,6 +31,7 @@
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/dispatch.h"
 #include "qga/channel.h"
+#include "qemu/bswap.h"
 #ifdef _WIN32
 #include "qga/service-win32.h"
 #include <windows.h>
@@ -53,6 +55,11 @@
 #endif
 #define QGA_SENTINEL_BYTE 0xFF
 
+typedef struct GAPersistentState {
+#define QGA_PSTATE_DEFAULT_FD_COUNTER 1000
+    int64_t fd_counter;
+} GAPersistentState;
+
 struct GAState {
     JSONMessageParser parser;
     GMainLoop *main_loop;
@@ -76,6 +83,8 @@ struct GAState {
 #ifdef CONFIG_FSFREEZE
     const char *fsfreeze_hook;
 #endif
+    const gchar *pstate_filepath;
+    GAPersistentState pstate;
 };
 
 struct GAState *ga_state;
@@ -85,6 +94,7 @@ static const char *ga_freeze_whitelist[] = {
     "guest-ping",
     "guest-info",
     "guest-sync",
+    "guest-sync-delimited",
     "guest-fsfreeze-status",
     "guest-fsfreeze-thaw",
     NULL
@@ -724,6 +734,171 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
 }
 #endif
 
+static void set_persistent_state_defaults(GAPersistentState *pstate)
+{
+    g_assert(pstate);
+    pstate->fd_counter = QGA_PSTATE_DEFAULT_FD_COUNTER;
+}
+
+static void persistent_state_from_keyfile(GAPersistentState *pstate,
+                                          GKeyFile *keyfile)
+{
+    g_assert(pstate);
+    g_assert(keyfile);
+    /* if any fields are missing, either because the file was tampered with
+     * by agents of chaos, or because the field wasn't present at the time the
+     * file was created, the best we can ever do is start over with the default
+     * values. so load them now, and ignore any errors in accessing key-value
+     * pairs
+     */
+    set_persistent_state_defaults(pstate);
+
+    if (g_key_file_has_key(keyfile, "global", "fd_counter", NULL)) {
+        pstate->fd_counter =
+            g_key_file_get_integer(keyfile, "global", "fd_counter", NULL);
+    }
+}
+
+static void persistent_state_to_keyfile(const GAPersistentState *pstate,
+                                        GKeyFile *keyfile)
+{
+    g_assert(pstate);
+    g_assert(keyfile);
+
+    g_key_file_set_integer(keyfile, "global", "fd_counter", pstate->fd_counter);
+}
+
+static gboolean write_persistent_state(const GAPersistentState *pstate,
+                                       const gchar *path)
+{
+    GKeyFile *keyfile = g_key_file_new();
+    GError *gerr = NULL;
+    gboolean ret = true;
+    gchar *data = NULL;
+    gsize data_len;
+
+    g_assert(pstate);
+
+    persistent_state_to_keyfile(pstate, keyfile);
+    data = g_key_file_to_data(keyfile, &data_len, &gerr);
+    if (gerr) {
+        g_critical("failed to convert persistent state to string: %s",
+                   gerr->message);
+        ret = false;
+        goto out;
+    }
+
+    g_file_set_contents(path, data, data_len, &gerr);
+    if (gerr) {
+        g_critical("failed to write persistent state to %s: %s",
+                    path, gerr->message);
+        ret = false;
+        goto out;
+    }
+
+out:
+    if (gerr) {
+        g_error_free(gerr);
+    }
+    if (keyfile) {
+        g_key_file_free(keyfile);
+    }
+    g_free(data);
+    return ret;
+}
+
+static gboolean read_persistent_state(GAPersistentState *pstate,
+                                      const gchar *path, gboolean frozen)
+{
+    GKeyFile *keyfile = NULL;
+    GError *gerr = NULL;
+    struct stat st;
+    gboolean ret = true;
+
+    g_assert(pstate);
+
+    if (stat(path, &st) == -1) {
+        /* it's okay if state file doesn't exist, but any other error
+         * indicates a permissions issue or some other misconfiguration
+         * that we likely won't be able to recover from.
+         */
+        if (errno != ENOENT) {
+            g_critical("unable to access state file at path %s: %s",
+                       path, strerror(errno));
+            ret = false;
+            goto out;
+        }
+
+        /* file doesn't exist. initialize state to default values and
+         * attempt to save now. (we could wait till later when we have
+         * modified state we need to commit, but if there's a problem,
+         * such as a missing parent directory, we want to catch it now)
+         *
+         * there is a potential scenario where someone either managed to
+         * update the agent from a version that didn't use a key store
+         * while qemu-ga thought the filesystem was frozen, or
+         * deleted the key store prior to issuing a fsfreeze, prior
+         * to restarting the agent. in this case we go ahead and defer
+         * initial creation till we actually have modified state to
+         * write, otherwise fail to recover from freeze.
+         */
+        set_persistent_state_defaults(pstate);
+        if (!frozen) {
+            ret = write_persistent_state(pstate, path);
+            if (!ret) {
+                g_critical("unable to create state file at path %s", path);
+                ret = false;
+                goto out;
+            }
+        }
+        ret = true;
+        goto out;
+    }
+
+    keyfile = g_key_file_new();
+    g_key_file_load_from_file(keyfile, path, 0, &gerr);
+    if (gerr) {
+        g_critical("error loading persistent state from path: %s, %s",
+                   path, gerr->message);
+        ret = false;
+        goto out;
+    }
+
+    persistent_state_from_keyfile(pstate, keyfile);
+
+out:
+    if (keyfile) {
+        g_key_file_free(keyfile);
+    }
+    if (gerr) {
+        g_error_free(gerr);
+    }
+
+    return ret;
+}
+
+int64_t ga_get_fd_handle(GAState *s, Error **errp)
+{
+    int64_t handle;
+
+    g_assert(s->pstate_filepath);
+    /* we blacklist commands and avoid operations that potentially require
+     * writing to disk when we're in a frozen state. this includes opening
+     * new files, so we should never get here in that situation
+     */
+    g_assert(!ga_is_frozen(s));
+
+    handle = s->pstate.fd_counter++;
+    if (s->pstate.fd_counter < 0) {
+        s->pstate.fd_counter = 0;
+    }
+    if (!write_persistent_state(&s->pstate, s->pstate_filepath)) {
+        error_setg(errp, "failed to commit persistent state to disk");
+    }
+
+    return handle;
+}
+
 int main(int argc, char **argv)
 {
     const char *sopt = "hVvdm:p:l:f:F::b:s:t:";
@@ -853,7 +1028,9 @@ int main(int argc, char **argv)
     ga_enable_logging(s);
     s->state_filepath_isfrozen = g_strdup_printf("%s/qga.state.isfrozen",
                                                  state_dir);
+    s->pstate_filepath = g_strdup_printf("%s/qga.state", state_dir);
     s->frozen = false;
+
 #ifndef _WIN32
     /* check if a previous instance of qemu-ga exited with filesystems' state
      * marked as frozen. this could be a stale value (a non-qemu-ga process
@@ -910,6 +1087,14 @@ int main(int argc, char **argv)
         }
     }
 
+    /* load persistent state from disk */
+    if (!read_persistent_state(&s->pstate,
+                               s->pstate_filepath,
+                               ga_is_frozen(s))) {
+        g_critical("failed to load persistent state");
+        goto out_bad;
+    }
+
     if (blacklist) {
         s->blacklist = blacklist;
         do {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index d91d903256..dac4e6f95f 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -83,6 +83,45 @@
 { 'command': 'guest-ping' }
 
 ##
+# @guest-get-time:
+#
+# Get the information about guest time relative to the Epoch
+# of 1970-01-01 in UTC.
+#
+# Returns: Time in nanoseconds.
+#
+# Since 1.5
+##
+{ 'command': 'guest-get-time',
+  'returns': 'int' }
+
+##
+# @guest-set-time:
+#
+# Set guest time.
+#
+# When a guest is paused or migrated to a file then loaded
+# from that file, the guest OS has no idea that there
+# was a big gap in the time. Depending on how long the
+# gap was, NTP might not be able to resynchronize the
+# guest.
+#
+# This command tries to set guest time to the given value,
+# then sets the Hardware Clock to the current System Time.
+# This will make it easier for a guest to resynchronize
+# without waiting for NTP.
+#
+# @time: time of nanoseconds, relative to the Epoch of
+#        1970-01-01 in UTC.
+#
+# Returns: Nothing on success.
+#
+# Since: 1.5
+##
+{ 'command': 'guest-set-time',
+  'data': { 'time': 'int' } }
+
+##
 # @GuestAgentCommandInfo:
 #
 # Information about guest agent commands.
@@ -515,3 +554,75 @@
 ##
 { 'command': 'guest-network-get-interfaces',
   'returns': ['GuestNetworkInterface'] }
+
+##
+# @GuestLogicalProcessor:
+#
+# @logical-id: Arbitrary guest-specific unique identifier of the VCPU.
+#
+# @online: Whether the VCPU is enabled.
+#
+# @can-offline: Whether offlining the VCPU is possible. This member is always
+#               filled in by the guest agent when the structure is returned,
+#               and always ignored on input (hence it can be omitted then).
+#
+# Since: 1.5
+##
+{ 'type': 'GuestLogicalProcessor',
+  'data': {'logical-id': 'int',
+           'online': 'bool',
+           '*can-offline': 'bool'} }
+
+##
+# @guest-get-vcpus:
+#
+# Retrieve the list of the guest's logical processors.
+#
+# This is a read-only operation.
+#
+# Returns: The list of all VCPUs the guest knows about. Each VCPU is put on the
+# list exactly once, but their order is unspecified.
+#
+# Since: 1.5
+##
+{ 'command': 'guest-get-vcpus',
+  'returns': ['GuestLogicalProcessor'] }
+
+##
+# @guest-set-vcpus:
+#
+# Attempt to reconfigure (currently: enable/disable) logical processors inside
+# the guest.
+#
+# The input list is processed node by node in order. In each node @logical-id
+# is used to look up the guest VCPU, for which @online specifies the requested
+# state. The set of distinct @logical-id's is only required to be a subset of
+# the guest-supported identifiers. There's no restriction on list length or on
+# repeating the same @logical-id (with possibly different @online field).
+# Preferably the input list should describe a modified subset of
+# @guest-get-vcpus' return value.
+#
+# Returns: The length of the initial sublist that has been successfully
+#          processed. The guest agent maximizes this value. Possible cases:
+#
+#          0:                if the @vcpus list was empty on input. Guest state
+#                            has not been changed. Otherwise,
+#
+#          Error:            processing the first node of @vcpus failed for the
+#                            reason returned. Guest state has not been changed.
+#                            Otherwise,
+#
+#          < length(@vcpus): more than zero initial nodes have been processed,
+#                            but not the entire @vcpus list. Guest state has
+#                            changed accordingly. To retrieve the error
+#                            (assuming it persists), repeat the call with the
+#                            successfully processed initial sublist removed.
+#                            Otherwise,
+#
+#          length(@vcpus):   call successful.
+#
+# Since: 1.5
+##
+{ 'command': 'guest-set-vcpus',
+  'data':    {'vcpus': ['GuestLogicalProcessor'] },
+  'returns': 'int' }
diff --git a/qga/service-win32.c b/qga/service-win32.c
index 09054565d3..843398a6c6 100644
--- a/qga/service-win32.c
+++ b/qga/service-win32.c
@@ -29,7 +29,7 @@ static int printf_win_error(const char *text)
         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
         (char *)&message, 0,
         NULL);
-    n = printf("%s. (Error: %d) %s", text, err, message);
+    n = printf("%s. (Error: %d) %s", text, (int)err, message);
     LocalFree(message);
 
     return n;
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 95022e259f..b370060848 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2716,6 +2716,24 @@ EQMP
     },
 
     {
+        .name       = "query-tpm",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_tpm,
+    },
+
+    {
+        .name       = "query-tpm-models",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_tpm_models,
+    },
+
+    {
+        .name       = "query-tpm-types",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_tpm_types,
+    },
+
+    {
         .name       = "chardev-add",
         .args_type  = "id:s,backend:q",
         .mhandler.cmd_new = qmp_marshal_input_chardev_add,
diff --git a/qom/cpu.c b/qom/cpu.c
index 0a2194d413..e242dcbeb4 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -21,6 +21,11 @@
 #include "qom/cpu.h"
 #include "qemu-common.h"
 
+void cpu_reset_interrupt(CPUState *cpu, int mask)
+{
+    cpu->interrupt_request &= ~mask;
+}
+
 void cpu_reset(CPUState *cpu)
 {
     CPUClass *klass = CPU_GET_CLASS(cpu);
@@ -33,7 +38,9 @@ void cpu_reset(CPUState *cpu)
 static void cpu_common_reset(CPUState *cpu)
 {
     cpu->exit_request = 0;
+    cpu->interrupt_request = 0;
     cpu->current_tb = NULL;
+    cpu->halted = 0;
 }
 
 ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
diff --git a/savevm.c b/savevm.c
index 147e2d232e..35c8d1e445 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1423,13 +1423,6 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
     return 0;
 }
 
-int vmstate_register(DeviceState *dev, int instance_id,
-                     const VMStateDescription *vmsd, void *opaque)
-{
-    return vmstate_register_with_alias_id(dev, instance_id, vmsd,
-                                          opaque, -1, 0);
-}
-
 void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
                         void *opaque)
 {
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index aea3d24e7d..8a9236d0a8 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -8,14 +8,6 @@
 
 #include "qemu/osdep.h"
 
-#define dprintf(_scd, _level, _fmt, ...)                                \
-    do {                                                                \
-        static unsigned __dprintf_counter = 0;                          \
-        if (_scd->debug >= _level) {                                    \
-            fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
-        }                                                               \
-    } while (0)
-
 typedef struct SpiceCharDriver {
     CharDriverState*      chr;
     SpiceCharDeviceInstance     sin;
@@ -24,7 +16,6 @@ typedef struct SpiceCharDriver {
     uint8_t               *buffer;
     uint8_t               *datapos;
     ssize_t               bufsize, datalen;
-    uint32_t              debug;
     QLIST_ENTRY(SpiceCharDriver) next;
 } SpiceCharDriver;
 
@@ -49,7 +40,6 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
         p += last_out;
     }
 
-    dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out);
     trace_spice_vmc_write(out, len + out);
     return out;
 }
@@ -59,7 +49,6 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
     int bytes = MIN(len, scd->datalen);
 
-    dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
     if (bytes > 0) {
         memcpy(buf, scd->datapos, bytes);
         scd->datapos += bytes;
@@ -84,11 +73,9 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
         chr_event = CHR_EVENT_BREAK;
         break;
     default:
-        dprintf(scd, 2, "%s: unknown %d\n", __func__, event);
         return;
     }
 
-    dprintf(scd, 2, "%s: %d\n", __func__, event);
     trace_spice_vmc_event(chr_event);
     qemu_chr_be_event(scd->chr, chr_event);
 }
@@ -141,7 +128,6 @@ static void vmc_register_interface(SpiceCharDriver *scd)
     if (scd->active) {
         return;
     }
-    dprintf(scd, 1, "%s\n", __func__);
     scd->sin.base.sif = &vmc_interface.base;
     qemu_spice_add_interface(&scd->sin.base);
     scd->active = true;
@@ -153,7 +139,6 @@ static void vmc_unregister_interface(SpiceCharDriver *scd)
     if (!scd->active) {
         return;
     }
-    dprintf(scd, 1, "%s\n", __func__);
     spice_server_remove_interface(&scd->sin.base);
     scd->active = false;
     trace_spice_vmc_unregister_interface(scd);
@@ -164,7 +149,6 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     SpiceCharDriver *s = chr->opaque;
 
-    dprintf(s, 2, "%s: %d\n", __func__, len);
     vmc_register_interface(s);
     assert(s->datalen == 0);
     if (s->bufsize < len) {
@@ -182,9 +166,13 @@ static void spice_chr_close(struct CharDriverState *chr)
 {
     SpiceCharDriver *s = chr->opaque;
 
-    printf("%s\n", __func__);
     vmc_unregister_interface(s);
     QLIST_REMOVE(s, next);
+
+    g_free((char *)s->sin.subtype);
+#if SPICE_SERVER_VERSION >= 0x000c02
+    g_free((char *)s->sin.portname);
+#endif
     g_free(s);
 }
 
@@ -217,18 +205,16 @@ static void print_allowed_subtypes(void)
     fprintf(stderr, "\n");
 }
 
-static CharDriverState *chr_open(QemuOpts *opts, const char *subtype)
+static CharDriverState *chr_open(const char *subtype)
 {
     CharDriverState *chr;
     SpiceCharDriver *s;
-    uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
 
     chr = g_malloc0(sizeof(CharDriverState));
     s = g_malloc0(sizeof(SpiceCharDriver));
     s->chr = chr;
-    s->debug = debug;
     s->active = false;
-    s->sin.subtype = subtype;
+    s->sin.subtype = g_strdup(subtype);
     chr->opaque = s;
     chr->chr_write = spice_chr_write;
     chr->chr_close = spice_chr_close;
@@ -240,35 +226,32 @@ static CharDriverState *chr_open(QemuOpts *opts, const char *subtype)
     return chr;
 }
 
-CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
+CharDriverState *qemu_chr_open_spice_vmc(const char *type)
 {
     CharDriverState *chr;
-    const char *name = qemu_opt_get(opts, "name");
     const char **psubtype = spice_server_char_device_recognized_subtypes();
-    const char *subtype = NULL;
 
-    if (name == NULL) {
+    if (type == NULL) {
         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
         print_allowed_subtypes();
         return NULL;
     }
-    for(;*psubtype != NULL; ++psubtype) {
-        if (strcmp(name, *psubtype) == 0) {
-            subtype = *psubtype;
+    for (; *psubtype != NULL; ++psubtype) {
+        if (strcmp(type, *psubtype) == 0) {
             break;
         }
     }
-    if (subtype == NULL) {
-        fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name);
+    if (*psubtype == NULL) {
+        fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
         print_allowed_subtypes();
         return NULL;
     }
 
-    chr = chr_open(opts, subtype);
+    chr = chr_open(type);
 
 #if SPICE_SERVER_VERSION < 0x000901
     /* See comment in vmc_state() */
-    if (strcmp(subtype, "vdagent") == 0) {
+    if (strcmp(type, "vdagent") == 0) {
         qemu_chr_generic_open(chr);
     }
 #endif
@@ -277,20 +260,19 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
 }
 
 #if SPICE_SERVER_VERSION >= 0x000c02
-CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts)
+CharDriverState *qemu_chr_open_spice_port(const char *name)
 {
     CharDriverState *chr;
     SpiceCharDriver *s;
-    const char *name = qemu_opt_get(opts, "name");
 
     if (name == NULL) {
         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
         return NULL;
     }
 
-    chr = chr_open(opts, "port");
+    chr = chr_open("port");
     s = chr->opaque;
-    s->sin.portname = name;
+    s->sin.portname = g_strdup(name);
 
     return chr;
 }
@@ -308,12 +290,38 @@ void qemu_spice_register_ports(void)
 }
 #endif
 
+static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
+                                     Error **errp)
+{
+    const char *name = qemu_opt_get(opts, "name");
+
+    if (name == NULL) {
+        error_setg(errp, "chardev: spice channel: no name given");
+        return;
+    }
+    backend->spicevmc = g_new0(ChardevSpiceChannel, 1);
+    backend->spicevmc->type = g_strdup(name);
+}
+
+static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
+                                      Error **errp)
+{
+    const char *name = qemu_opt_get(opts, "name");
+
+    if (name == NULL) {
+        error_setg(errp, "chardev: spice port: no name given");
+        return;
+    }
+    backend->spiceport = g_new0(ChardevSpicePort, 1);
+    backend->spiceport->fqdn = g_strdup(name);
+}
+
 static void register_types(void)
 {
-    register_char_driver("spicevmc", qemu_chr_open_spice);
-#if SPICE_SERVER_VERSION >= 0x000c02
-    register_char_driver("spiceport", qemu_chr_open_spice_port);
-#endif
+    register_char_driver_qapi("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC,
+                              qemu_chr_parse_spice_vmc);
+    register_char_driver_qapi("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT,
+                              qemu_chr_parse_spice_port);
 }
 
 type_init(register_types);
diff --git a/stubs/vmstate.c b/stubs/vmstate.c
index 3682af599e..778bc3fc69 100644
--- a/stubs/vmstate.c
+++ b/stubs/vmstate.c
@@ -1,6 +1,8 @@
 #include "qemu-common.h"
 #include "migration/vmstate.h"
 
+const VMStateDescription vmstate_dummy = {};
+
 int vmstate_register_with_alias_id(DeviceState *dev,
                                    int instance_id,
                                    const VMStateDescription *vmsd,
diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h
index 252bd14821..32ee286db3 100644
--- a/target-alpha/cpu-qom.h
+++ b/target-alpha/cpu-qom.h
@@ -74,4 +74,6 @@ static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env)
 
 #define ENV_OFFSET offsetof(AlphaCPU, env)
 
+void alpha_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index cec9989925..cad1716601 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -263,6 +263,7 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
     dc->realize = alpha_cpu_realizefn;
 
     cc->class_by_name = alpha_cpu_class_by_name;
+    cc->do_interrupt = alpha_cpu_do_interrupt;
 }
 
 static const TypeInfo alpha_cpu_type_info = {
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index f1db6518ce..2156a1e5fd 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -449,7 +449,6 @@ int cpu_alpha_signal_handler(int host_signum, void *pinfo,
 int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, uint64_t address, int rw,
                                 int mmu_idx);
 #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
-void do_interrupt (CPUAlphaState *env);
 void do_restore_state(CPUAlphaState *, uintptr_t retaddr);
 void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int);
 void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t);
@@ -517,8 +516,6 @@ static inline void cpu_set_tls(CPUAlphaState *env, target_ulong newtls)
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUAlphaState *env = &ALPHA_CPU(cpu)->env;
-
     /* Here we are checking to see if the CPU should wake up from HALT.
        We will have gotten into this state only for WTINT from PALmode.  */
     /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU
@@ -526,7 +523,7 @@ static inline bool cpu_has_work(CPUState *cpu)
        assume that if a CPU really wants to stay asleep, it will mask
        interrupts at the chipset level, which will prevent these bits
        from being set in the first place.  */
-    return env->interrupt_request & (CPU_INTERRUPT_HARD
+    return cpu->interrupt_request & (CPU_INTERRUPT_HARD
                                      | CPU_INTERRUPT_TIMER
                                      | CPU_INTERRUPT_SMP
                                      | CPU_INTERRUPT_MCHK);
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 22c9c6ec8c..5741ec25ea 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -345,8 +345,10 @@ int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong addr, int rw,
 }
 #endif /* USER_ONLY */
 
-void do_interrupt (CPUAlphaState *env)
+void alpha_cpu_do_interrupt(CPUState *cs)
 {
+    AlphaCPU *cpu = ALPHA_CPU(cs);
+    CPUAlphaState *env = &cpu->env;
     int i = env->exception_index;
 
     if (qemu_loglevel_mask(CPU_LOG_INT)) {
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 657f5e1e5f..4db16db462 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1686,7 +1686,8 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
     case 253:
         /* WAIT */
         tmp = tcg_const_i64(1);
-        tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUAlphaState, halted));
+        tcg_gen_st32_i64(tmp, cpu_env, -offsetof(AlphaCPU, env) +
+                                       offsetof(CPUState, halted));
         return gen_excp(ctx, EXCP_HLT, 0);
 
     case 252:
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7539727768..25895509be 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -113,4 +113,7 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
 
 void register_cp_regs_for_features(ARMCPU *cpu);
 
+void arm_cpu_do_interrupt(CPUState *cpu);
+void arm_v7m_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 5dfcb740d9..a1e90939d6 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -412,6 +412,15 @@ static void cortex_m3_initfn(Object *obj)
     cpu->midr = 0x410fc231;
 }
 
+static void arm_v7m_class_init(ObjectClass *oc, void *data)
+{
+#ifndef CONFIG_USER_ONLY
+    CPUClass *cc = CPU_CLASS(oc);
+
+    cc->do_interrupt = arm_v7m_cpu_do_interrupt;
+#endif
+}
+
 static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
     { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
@@ -752,6 +761,7 @@ static void arm_any_initfn(Object *obj)
 typedef struct ARMCPUInfo {
     const char *name;
     void (*initfn)(Object *obj);
+    void (*class_init)(ObjectClass *oc, void *data);
 } ARMCPUInfo;
 
 static const ARMCPUInfo arm_cpus[] = {
@@ -766,7 +776,8 @@ static const ARMCPUInfo arm_cpus[] = {
     { .name = "arm1136",     .initfn = arm1136_initfn },
     { .name = "arm1176",     .initfn = arm1176_initfn },
     { .name = "arm11mpcore", .initfn = arm11mpcore_initfn },
-    { .name = "cortex-m3",   .initfn = cortex_m3_initfn },
+    { .name = "cortex-m3",   .initfn = cortex_m3_initfn,
+                             .class_init = arm_v7m_class_init },
     { .name = "cortex-a8",   .initfn = cortex_a8_initfn },
     { .name = "cortex-a9",   .initfn = cortex_a9_initfn },
     { .name = "cortex-a15",  .initfn = cortex_a15_initfn },
@@ -802,6 +813,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
     cc->reset = arm_cpu_reset;
 
     cc->class_by_name = arm_cpu_class_by_name;
+    cc->do_interrupt = arm_cpu_do_interrupt;
 }
 
 static void cpu_register(const ARMCPUInfo *info)
@@ -811,6 +823,7 @@ static void cpu_register(const ARMCPUInfo *info)
         .instance_size = sizeof(ARMCPU),
         .instance_init = info->initfn,
         .class_size = sizeof(ARMCPUClass),
+        .class_init = info->class_init,
     };
 
     type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c28a0d94c3..2b97221209 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -236,7 +236,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model);
 void arm_translate_init(void);
 void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
 int cpu_arm_exec(CPUARMState *s);
-void do_interrupt(CPUARMState *);
 int bank_number(int mode);
 void switch_mode(CPUARMState *, int);
 uint32_t do_arm_semihosting(CPUARMState *env);
@@ -722,9 +721,7 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUARMState *env = &ARM_CPU(cpu)->env;
-
-    return env->interrupt_request &
+    return cpu->interrupt_request &
         (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
 }
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 6cad936d3e..fd055e89f2 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -764,7 +764,7 @@ static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri,
                           uint64_t value)
 {
     /* Wait-for-interrupt (deprecated) */
-    cpu_interrupt(env, CPU_INTERRUPT_HALT);
+    cpu_interrupt(CPU(arm_env_get_cpu(env)), CPU_INTERRUPT_HALT);
     return 0;
 }
 
@@ -1567,8 +1567,11 @@ uint32_t HELPER(rbit)(uint32_t x)
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUARMState *env)
+void arm_cpu_do_interrupt(CPUState *cs)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
     env->exception_index = -1;
 }
 
@@ -1722,8 +1725,10 @@ static void do_v7m_exception_exit(CPUARMState *env)
        pointer.  */
 }
 
-static void do_interrupt_v7m(CPUARMState *env)
+void arm_v7m_cpu_do_interrupt(CPUState *cs)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
     uint32_t xpsr = xpsr_read(env);
     uint32_t lr;
     uint32_t addr;
@@ -1799,17 +1804,17 @@ static void do_interrupt_v7m(CPUARMState *env)
 }
 
 /* Handle a CPU exception.  */
-void do_interrupt(CPUARMState *env)
+void arm_cpu_do_interrupt(CPUState *cs)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
     uint32_t addr;
     uint32_t mask;
     int new_mode;
     uint32_t offset;
 
-    if (IS_M(env)) {
-        do_interrupt_v7m(env);
-        return;
-    }
+    assert(!IS_M(env));
+
     /* TODO: Vectored interrupt controller.  */
     switch (env->exception_index) {
     case EXCP_UDEF:
@@ -1907,7 +1912,7 @@ void do_interrupt(CPUARMState *env)
     }
     env->regs[14] = env->regs[15] + offset;
     env->regs[15] = addr;
-    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 
 /* Check section/page access permissions.
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index a52231346c..a918e5b27a 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -218,8 +218,10 @@ uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
 
 void HELPER(wfi)(CPUARMState *env)
 {
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+
     env->exception_index = EXCP_HLT;
-    env->halted = 1;
+    cs->halted = 1;
     cpu_loop_exit(env);
 }
 
diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h
index 11e528661d..deea1d804b 100644
--- a/target-cris/cpu-qom.h
+++ b/target-cris/cpu-qom.h
@@ -73,4 +73,6 @@ static inline CRISCPU *cris_env_get_cpu(CPUCRISState *env)
 
 #define ENV_OFFSET offsetof(CRISCPU, env)
 
+void cris_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 7974be33f2..95cbf399d9 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -243,6 +243,7 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
     cc->reset = cris_cpu_reset;
 
     cc->class_by_name = cris_cpu_class_by_name;
+    cc->do_interrupt = cris_cpu_do_interrupt;
 }
 
 static const TypeInfo cris_cpu_type_info = {
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index ebf2d4027f..dbd7d36870 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -175,7 +175,6 @@ typedef struct CPUCRISState {
 
 CRISCPU *cpu_cris_init(const char *cpu_model);
 int cpu_cris_exec(CPUCRISState *s);
-void do_interrupt(CPUCRISState *env);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
@@ -289,9 +288,7 @@ void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUCRISState *env = &CRIS_CPU(cpu)->env;
-
-    return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+    return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
 }
 
 #include "exec/exec-all.h"
diff --git a/target-cris/helper.c b/target-cris/helper.c
index 6e75e9819e..e1ef7bcc0b 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -36,19 +36,22 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUCRISState *env)
+void cris_cpu_do_interrupt(CPUState *cs)
 {
-	env->exception_index = -1;
-	env->pregs[PR_ERP] = env->pc;
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
+
+    env->exception_index = -1;
+    env->pregs[PR_ERP] = env->pc;
 }
 
 int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw,
                               int mmu_idx)
 {
-	env->exception_index = 0xaa;
-	env->pregs[PR_EDA] = address;
-	cpu_dump_state(env, stderr, fprintf, 0);
-	return 1;
+    env->exception_index = 0xaa;
+    env->pregs[PR_EDA] = address;
+    cpu_dump_state(env, stderr, fprintf, 0);
+    return 1;
 }
 
 #else /* !CONFIG_USER_ONLY */
@@ -56,211 +59,214 @@ int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw,
 
 static void cris_shift_ccs(CPUCRISState *env)
 {
-	uint32_t ccs;
-	/* Apply the ccs shift.  */
-	ccs = env->pregs[PR_CCS];
-	ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
-	env->pregs[PR_CCS] = ccs;
+    uint32_t ccs;
+    /* Apply the ccs shift.  */
+    ccs = env->pregs[PR_CCS];
+    ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
+    env->pregs[PR_CCS] = ccs;
 }
 
-int cpu_cris_handle_mmu_fault (CPUCRISState *env, target_ulong address, int rw,
-                               int mmu_idx)
+int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw,
+                              int mmu_idx)
 {
-	struct cris_mmu_result res;
-	int prot, miss;
-	int r = -1;
-	target_ulong phy;
-
-	D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
-	miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
-				  rw, mmu_idx, 0);
-	if (miss)
-	{
-		if (env->exception_index == EXCP_BUSFAULT)
-			cpu_abort(env,
-				  "CRIS: Illegal recursive bus fault."
-				 "addr=%x rw=%d\n",
-				 address, rw);
-
-		env->pregs[PR_EDA] = address;
-		env->exception_index = EXCP_BUSFAULT;
-		env->fault_vector = res.bf_vec;
-		r = 1;
-	}
-	else
-	{
-		/*
-		 * Mask off the cache selection bit. The ETRAX busses do not
-		 * see the top bit.
-		 */
-		phy = res.phy & ~0x80000000;
-		prot = res.prot;
-		tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
-                             prot, mmu_idx, TARGET_PAGE_SIZE);
-                r = 0;
-	}
-	if (r > 0)
-            D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
-                  __func__, r, env->interrupt_request, address, res.phy,
-                  res.bf_vec, env->pc);
-	return r;
+    D(CPUState *cpu = CPU(cris_env_get_cpu(env)));
+    struct cris_mmu_result res;
+    int prot, miss;
+    int r = -1;
+    target_ulong phy;
+
+    D(printf("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
+    miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
+                              rw, mmu_idx, 0);
+    if (miss) {
+        if (env->exception_index == EXCP_BUSFAULT) {
+            cpu_abort(env,
+                      "CRIS: Illegal recursive bus fault."
+                      "addr=%x rw=%d\n",
+                      address, rw);
+        }
+
+        env->pregs[PR_EDA] = address;
+        env->exception_index = EXCP_BUSFAULT;
+        env->fault_vector = res.bf_vec;
+        r = 1;
+    } else {
+        /*
+         * Mask off the cache selection bit. The ETRAX busses do not
+         * see the top bit.
+         */
+        phy = res.phy & ~0x80000000;
+        prot = res.prot;
+        tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
+                     prot, mmu_idx, TARGET_PAGE_SIZE);
+        r = 0;
+    }
+    if (r > 0) {
+        D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
+              __func__, r, cpu->interrupt_request, address, res.phy,
+              res.bf_vec, env->pc);
+    }
+    return r;
 }
 
 static void do_interruptv10(CPUCRISState *env)
 {
-	int ex_vec = -1;
-
-	D_LOG( "exception index=%d interrupt_req=%d\n",
-		   env->exception_index,
-		   env->interrupt_request);
-
-	assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
-	switch (env->exception_index)
-	{
-		case EXCP_BREAK:
-			/* These exceptions are genereated by the core itself.
-			   ERP should point to the insn following the brk.  */
-			ex_vec = env->trap_vector;
-			env->pregs[PRV10_BRP] = env->pc;
-			break;
-
-		case EXCP_NMI:
-			/* NMI is hardwired to vector zero.  */
-			ex_vec = 0;
-			env->pregs[PR_CCS] &= ~M_FLAG_V10;
-			env->pregs[PRV10_BRP] = env->pc;
-			break;
-
-		case EXCP_BUSFAULT:
-                        cpu_abort(env, "Unhandled busfault");
-			break;
-
-		default:
-			/* The interrupt controller gives us the vector.  */
-			ex_vec = env->interrupt_vector;
-			/* Normal interrupts are taken between
-			   TB's.  env->pc is valid here.  */
-			env->pregs[PR_ERP] = env->pc;
-			break;
-	}
-
-	if (env->pregs[PR_CCS] & U_FLAG) {
-		/* Swap stack pointers.  */
-		env->pregs[PR_USP] = env->regs[R_SP];
-		env->regs[R_SP] = env->ksp;
-	}
-
-	/* Now that we are in kernel mode, load the handlers address.  */
-        env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
-	env->locked_irq = 1;
-	env->pregs[PR_CCS] |= F_FLAG_V10; /* set F.  */
-
-	qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 
-		      __func__, env->pc, ex_vec, 
-		      env->pregs[PR_CCS],
-		      env->pregs[PR_PID], 
-		      env->pregs[PR_ERP]);
+    D(CPUState *cs = CPU(cris_env_get_cpu(env)));
+    int ex_vec = -1;
+
+    D_LOG("exception index=%d interrupt_req=%d\n",
+          env->exception_index,
+          cs->interrupt_request);
+
+    assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
+    switch (env->exception_index) {
+    case EXCP_BREAK:
+        /* These exceptions are genereated by the core itself.
+           ERP should point to the insn following the brk.  */
+        ex_vec = env->trap_vector;
+        env->pregs[PRV10_BRP] = env->pc;
+        break;
+
+    case EXCP_NMI:
+        /* NMI is hardwired to vector zero.  */
+        ex_vec = 0;
+        env->pregs[PR_CCS] &= ~M_FLAG_V10;
+        env->pregs[PRV10_BRP] = env->pc;
+        break;
+
+    case EXCP_BUSFAULT:
+        cpu_abort(env, "Unhandled busfault");
+        break;
+
+    default:
+        /* The interrupt controller gives us the vector.  */
+        ex_vec = env->interrupt_vector;
+        /* Normal interrupts are taken between
+           TB's.  env->pc is valid here.  */
+        env->pregs[PR_ERP] = env->pc;
+        break;
+    }
+
+    if (env->pregs[PR_CCS] & U_FLAG) {
+        /* Swap stack pointers.  */
+        env->pregs[PR_USP] = env->regs[R_SP];
+        env->regs[R_SP] = env->ksp;
+    }
+
+    /* Now that we are in kernel mode, load the handlers address.  */
+    env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
+    env->locked_irq = 1;
+    env->pregs[PR_CCS] |= F_FLAG_V10; /* set F.  */
+
+    qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
+                  __func__, env->pc, ex_vec,
+                  env->pregs[PR_CCS],
+                  env->pregs[PR_PID],
+                  env->pregs[PR_ERP]);
 }
 
-void do_interrupt(CPUCRISState *env)
+void cris_cpu_do_interrupt(CPUState *cs)
 {
-	int ex_vec = -1;
-
-	if (env->pregs[PR_VR] < 32)
-		return do_interruptv10(env);
-
-	D_LOG( "exception index=%d interrupt_req=%d\n",
-		   env->exception_index,
-		   env->interrupt_request);
-
-	switch (env->exception_index)
-	{
-		case EXCP_BREAK:
-			/* These exceptions are genereated by the core itself.
-			   ERP should point to the insn following the brk.  */
-			ex_vec = env->trap_vector;
-			env->pregs[PR_ERP] = env->pc;
-			break;
-
-		case EXCP_NMI:
-			/* NMI is hardwired to vector zero.  */
-			ex_vec = 0;
-			env->pregs[PR_CCS] &= ~M_FLAG_V32;
-			env->pregs[PR_NRP] = env->pc;
-			break;
-
-		case EXCP_BUSFAULT:
-			ex_vec = env->fault_vector;
-			env->pregs[PR_ERP] = env->pc;
-			break;
-
-		default:
-			/* The interrupt controller gives us the vector.  */
-			ex_vec = env->interrupt_vector;
-			/* Normal interrupts are taken between
-			   TB's.  env->pc is valid here.  */
-			env->pregs[PR_ERP] = env->pc;
-			break;
-	}
-
-	/* Fill in the IDX field.  */
-	env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
-
-	if (env->dslot) {
-		D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
-			  " ERP=%x pid=%x ccs=%x cc=%d %x\n",
-			  ex_vec, env->pc, env->dslot,
-			  env->regs[R_SP],
-			  env->pregs[PR_ERP], env->pregs[PR_PID],
-			  env->pregs[PR_CCS],
-			  env->cc_op, env->cc_mask);
-		/* We loose the btarget, btaken state here so rexec the
-		   branch.  */
-		env->pregs[PR_ERP] -= env->dslot;
-		/* Exception starts with dslot cleared.  */
-		env->dslot = 0;
-	}
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
+    int ex_vec = -1;
+
+    if (env->pregs[PR_VR] < 32) {
+        return do_interruptv10(env);
+    }
+
+    D_LOG("exception index=%d interrupt_req=%d\n",
+          env->exception_index,
+          cs->interrupt_request);
+
+    switch (env->exception_index) {
+    case EXCP_BREAK:
+        /* These exceptions are genereated by the core itself.
+           ERP should point to the insn following the brk.  */
+        ex_vec = env->trap_vector;
+        env->pregs[PR_ERP] = env->pc;
+        break;
+
+    case EXCP_NMI:
+        /* NMI is hardwired to vector zero.  */
+        ex_vec = 0;
+        env->pregs[PR_CCS] &= ~M_FLAG_V32;
+        env->pregs[PR_NRP] = env->pc;
+        break;
+
+    case EXCP_BUSFAULT:
+        ex_vec = env->fault_vector;
+        env->pregs[PR_ERP] = env->pc;
+        break;
+
+    default:
+        /* The interrupt controller gives us the vector.  */
+        ex_vec = env->interrupt_vector;
+        /* Normal interrupts are taken between
+           TB's.  env->pc is valid here.  */
+        env->pregs[PR_ERP] = env->pc;
+        break;
+    }
+
+    /* Fill in the IDX field.  */
+    env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
+
+    if (env->dslot) {
+        D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
+              " ERP=%x pid=%x ccs=%x cc=%d %x\n",
+              ex_vec, env->pc, env->dslot,
+              env->regs[R_SP],
+              env->pregs[PR_ERP], env->pregs[PR_PID],
+              env->pregs[PR_CCS],
+              env->cc_op, env->cc_mask);
+        /* We loose the btarget, btaken state here so rexec the
+           branch.  */
+        env->pregs[PR_ERP] -= env->dslot;
+        /* Exception starts with dslot cleared.  */
+        env->dslot = 0;
+    }
 	
-	if (env->pregs[PR_CCS] & U_FLAG) {
-		/* Swap stack pointers.  */
-		env->pregs[PR_USP] = env->regs[R_SP];
-		env->regs[R_SP] = env->ksp;
-	}
-
-	/* Apply the CRIS CCS shift. Clears U if set.  */
-	cris_shift_ccs(env);
-
-	/* Now that we are in kernel mode, load the handlers address.
-	   This load may not fault, real hw leaves that behaviour as
-	   undefined.  */
-        env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
-
-	/* Clear the excption_index to avoid spurios hw_aborts for recursive
-	   bus faults.  */
-	env->exception_index = -1;
-
-	D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
-		   __func__, env->pc, ex_vec,
-		   env->pregs[PR_CCS],
-		   env->pregs[PR_PID], 
-		   env->pregs[PR_ERP]);
+    if (env->pregs[PR_CCS] & U_FLAG) {
+        /* Swap stack pointers.  */
+        env->pregs[PR_USP] = env->regs[R_SP];
+        env->regs[R_SP] = env->ksp;
+    }
+
+    /* Apply the CRIS CCS shift. Clears U if set.  */
+    cris_shift_ccs(env);
+
+    /* Now that we are in kernel mode, load the handlers address.
+       This load may not fault, real hw leaves that behaviour as
+       undefined.  */
+    env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
+
+    /* Clear the excption_index to avoid spurios hw_aborts for recursive
+       bus faults.  */
+    env->exception_index = -1;
+
+    D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
+          __func__, env->pc, ex_vec,
+          env->pregs[PR_CCS],
+          env->pregs[PR_PID],
+          env->pregs[PR_ERP]);
 }
 
 hwaddr cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr)
 {
-	uint32_t phy = addr;
-	struct cris_mmu_result res;
-	int miss;
-
-	miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
-	/* If D TLB misses, try I TLB.  */
-	if (miss) {
-		miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
-	}
-
-	if (!miss)
-		phy = res.phy;
-	D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
-	return phy;
+    uint32_t phy = addr;
+    struct cris_mmu_result res;
+    int miss;
+
+    miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
+    /* If D TLB misses, try I TLB.  */
+    if (miss) {
+        miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
+    }
+
+    if (!miss) {
+        phy = res.phy;
+    }
+    D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
+    return phy;
 }
 #endif
diff --git a/target-cris/translate.c b/target-cris/translate.c
index ec71ef4721..dbcb811b7b 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -2888,7 +2888,8 @@ static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc)
     cris_cc_mask(dc, 0);
 
     if (dc->op2 == 15) {
-        t_gen_mov_env_TN(halted, tcg_const_tl(1));
+        tcg_gen_st_i32(tcg_const_i32(1), cpu_env,
+                       -offsetof(CRISCPU, env) + offsetof(CPUState, halted));
         tcg_gen_movi_tl(env_pc, dc->pc + 2);
         t_gen_raise_exception(EXCP_HLT);
         return 2;
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index b7bdcb6892..08f9eb67b2 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -76,4 +76,14 @@ static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
 
 #define ENV_OFFSET offsetof(X86CPU, env)
 
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vmstate_x86_cpu;
+#endif
+
+/**
+ * x86_cpu_do_interrupt:
+ * @cpu: vCPU the interrupt is to be handled by.
+ */
+void x86_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 8fb736a5b4..a0640db9e3 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2014,7 +2014,7 @@ static void x86_cpu_reset(CPUState *s)
         apic_designate_bsp(env->apic_state);
     }
 
-    env->halted = !cpu_is_bsp(cpu);
+    s->halted = !cpu_is_bsp(cpu);
 #endif
 }
 
@@ -2250,6 +2250,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
 
     xcc->parent_reset = cc->reset;
     cc->reset = x86_cpu_reset;
+
+    cc->do_interrupt = x86_cpu_do_interrupt;
+    cpu_class_set_vmsd(cc, &vmstate_x86_cpu);
 }
 
 static const TypeInfo x86_cpu_type_info = {
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 493dda8bb6..48f41ca3e3 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -967,6 +967,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env,
 static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu,
                                                int sipi_vector)
 {
+    CPUState *cs = CPU(cpu);
     CPUX86State *env = &cpu->env;
 
     env->eip = 0;
@@ -974,7 +975,7 @@ static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu,
                            sipi_vector << 12,
                            env->segs[R_CS].limit,
                            env->segs[R_CS].flags);
-    env->halted = 0;
+    cs->halted = 0;
 }
 
 int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
@@ -1092,8 +1093,6 @@ static inline CPUX86State *cpu_init(const char *cpu_model)
 #define cpu_list x86_cpu_list
 #define cpudef_setup	x86_cpudef_setup
 
-#define CPU_SAVE_VERSION 12
-
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
 #define MMU_MODE1_SUFFIX _user
@@ -1168,17 +1167,18 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp)
 #include "hw/apic.h"
 #endif
 
-static inline bool cpu_has_work(CPUState *cpu)
+static inline bool cpu_has_work(CPUState *cs)
 {
-    CPUX86State *env = &X86_CPU(cpu)->env;
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
 
-    return ((env->interrupt_request & (CPU_INTERRUPT_HARD |
-                                       CPU_INTERRUPT_POLL)) &&
+    return ((cs->interrupt_request & (CPU_INTERRUPT_HARD |
+                                      CPU_INTERRUPT_POLL)) &&
             (env->eflags & IF_MASK)) ||
-           (env->interrupt_request & (CPU_INTERRUPT_NMI |
-                                      CPU_INTERRUPT_INIT |
-                                      CPU_INTERRUPT_SIPI |
-                                      CPU_INTERRUPT_MCE));
+           (cs->interrupt_request & (CPU_INTERRUPT_NMI |
+                                     CPU_INTERRUPT_INIT |
+                                     CPU_INTERRUPT_SIPI |
+                                     CPU_INTERRUPT_MCE));
 }
 
 #include "exec/exec-all.h"
@@ -1252,8 +1252,7 @@ void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
                                    uint64_t param);
 void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1);
 
-/* op_helper.c */
-void do_interrupt(CPUX86State *env);
+/* seg_helper.c */
 void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
 
 void do_smm_enter(CPUX86State *env1);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 82a731c77d..9449a0c49d 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -182,6 +182,7 @@ done:
 void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     int eflags, i, nb;
     char cc_op_name[32];
     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
@@ -225,7 +226,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
                     (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
                     (env->a20_mask >> 20) & 1,
                     (env->hflags >> HF_SMM_SHIFT) & 1,
-                    env->halted);
+                    cs->halted);
     } else
 #endif
     {
@@ -252,7 +253,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
                     (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
                     (env->a20_mask >> 20) & 1,
                     (env->hflags >> HF_SMM_SHIFT) & 1,
-                    env->halted);
+                    cs->halted);
     }
 
     for(i = 0; i < 6; i++) {
@@ -388,7 +389,7 @@ void x86_cpu_set_a20(X86CPU *cpu, int a20_state)
 #endif
         /* if the cpu is currently executing code, we must unlink it and
            all the potentially executing TB */
-        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
+        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_EXITTB);
 
         /* when a20 is changed, all the MMU mappings are invalid, so
            we must flush everything */
@@ -1168,7 +1169,7 @@ static void do_inject_x86_mce(void *data)
         banks[3] = params->misc;
         cenv->mcg_status = params->mcg_status;
         banks[1] = params->status;
-        cpu_interrupt(cenv, CPU_INTERRUPT_MCE);
+        cpu_interrupt(cpu, CPU_INTERRUPT_MCE);
     } else if (!(banks[1] & MCI_STATUS_VAL)
                || !(banks[1] & MCI_STATUS_UC)) {
         if (banks[1] & MCI_STATUS_VAL) {
@@ -1240,7 +1241,7 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
     if (kvm_enabled()) {
         env->tpr_access_type = access;
 
-        cpu_interrupt(env, CPU_INTERRUPT_TPR);
+        cpu_interrupt(CPU(x86_env_get_cpu(env)), CPU_INTERRUPT_TPR);
     } else {
         cpu_restore_state(env, env->mem_io_pc);
 
@@ -1281,12 +1282,13 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
 #if !defined(CONFIG_USER_ONLY)
 void do_cpu_init(X86CPU *cpu)
 {
+    CPUState *cs = CPU(cpu);
     CPUX86State *env = &cpu->env;
-    int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI;
+    int sipi = cs->interrupt_request & CPU_INTERRUPT_SIPI;
     uint64_t pat = env->pat;
 
-    cpu_reset(CPU(cpu));
-    env->interrupt_request = sipi;
+    cpu_reset(cs);
+    cs->interrupt_request = sipi;
     env->pat = pat;
     apic_init_reset(env->apic_state);
 }
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 0cf413dbfd..df30fa6ed6 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1460,17 +1460,18 @@ static int kvm_put_mp_state(X86CPU *cpu)
 
 static int kvm_get_mp_state(X86CPU *cpu)
 {
+    CPUState *cs = CPU(cpu);
     CPUX86State *env = &cpu->env;
     struct kvm_mp_state mp_state;
     int ret;
 
-    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state);
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state);
     if (ret < 0) {
         return ret;
     }
     env->mp_state = mp_state.mp_state;
     if (kvm_irqchip_in_kernel()) {
-        env->halted = (mp_state.mp_state == KVM_MP_STATE_HALTED);
+        cs->halted = (mp_state.mp_state == KVM_MP_STATE_HALTED);
     }
     return 0;
 }
@@ -1762,8 +1763,8 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
     int ret;
 
     /* Inject NMI */
-    if (env->interrupt_request & CPU_INTERRUPT_NMI) {
-        env->interrupt_request &= ~CPU_INTERRUPT_NMI;
+    if (cpu->interrupt_request & CPU_INTERRUPT_NMI) {
+        cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
         DPRINTF("injected NMI\n");
         ret = kvm_vcpu_ioctl(cpu, KVM_NMI);
         if (ret < 0) {
@@ -1775,18 +1776,18 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
     if (!kvm_irqchip_in_kernel()) {
         /* Force the VCPU out of its inner loop to process any INIT requests
          * or pending TPR access reports. */
-        if (env->interrupt_request &
+        if (cpu->interrupt_request &
             (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) {
             cpu->exit_request = 1;
         }
 
         /* Try to inject an interrupt if the guest can accept it */
         if (run->ready_for_interrupt_injection &&
-            (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
             (env->eflags & IF_MASK)) {
             int irq;
 
-            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+            cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
             irq = cpu_get_pic_interrupt(env);
             if (irq >= 0) {
                 struct kvm_interrupt intr;
@@ -1806,7 +1807,7 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
          * interrupt, request an interrupt window exit.  This will
          * cause a return to userspace as soon as the guest is ready to
          * receive interrupts. */
-        if ((env->interrupt_request & CPU_INTERRUPT_HARD)) {
+        if ((cpu->interrupt_request & CPU_INTERRUPT_HARD)) {
             run->request_interrupt_window = 1;
         } else {
             run->request_interrupt_window = 0;
@@ -1836,11 +1837,11 @@ int kvm_arch_process_async_events(CPUState *cs)
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *env = &cpu->env;
 
-    if (env->interrupt_request & CPU_INTERRUPT_MCE) {
+    if (cs->interrupt_request & CPU_INTERRUPT_MCE) {
         /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */
         assert(env->mcg_cap);
 
-        env->interrupt_request &= ~CPU_INTERRUPT_MCE;
+        cs->interrupt_request &= ~CPU_INTERRUPT_MCE;
 
         kvm_cpu_synchronize_state(env);
 
@@ -1853,7 +1854,7 @@ int kvm_arch_process_async_events(CPUState *cs)
         env->exception_injected = EXCP12_MCHK;
         env->has_error_code = 0;
 
-        env->halted = 0;
+        cs->halted = 0;
         if (kvm_irqchip_in_kernel() && env->mp_state == KVM_MP_STATE_HALTED) {
             env->mp_state = KVM_MP_STATE_RUNNABLE;
         }
@@ -1863,41 +1864,42 @@ int kvm_arch_process_async_events(CPUState *cs)
         return 0;
     }
 
-    if (env->interrupt_request & CPU_INTERRUPT_POLL) {
-        env->interrupt_request &= ~CPU_INTERRUPT_POLL;
+    if (cs->interrupt_request & CPU_INTERRUPT_POLL) {
+        cs->interrupt_request &= ~CPU_INTERRUPT_POLL;
         apic_poll_irq(env->apic_state);
     }
-    if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+    if (((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
          (env->eflags & IF_MASK)) ||
-        (env->interrupt_request & CPU_INTERRUPT_NMI)) {
-        env->halted = 0;
+        (cs->interrupt_request & CPU_INTERRUPT_NMI)) {
+        cs->halted = 0;
     }
-    if (env->interrupt_request & CPU_INTERRUPT_INIT) {
+    if (cs->interrupt_request & CPU_INTERRUPT_INIT) {
         kvm_cpu_synchronize_state(env);
         do_cpu_init(cpu);
     }
-    if (env->interrupt_request & CPU_INTERRUPT_SIPI) {
+    if (cs->interrupt_request & CPU_INTERRUPT_SIPI) {
         kvm_cpu_synchronize_state(env);
         do_cpu_sipi(cpu);
     }
-    if (env->interrupt_request & CPU_INTERRUPT_TPR) {
-        env->interrupt_request &= ~CPU_INTERRUPT_TPR;
+    if (cs->interrupt_request & CPU_INTERRUPT_TPR) {
+        cs->interrupt_request &= ~CPU_INTERRUPT_TPR;
         kvm_cpu_synchronize_state(env);
         apic_handle_tpr_access_report(env->apic_state, env->eip,
                                       env->tpr_access_type);
     }
 
-    return env->halted;
+    return cs->halted;
 }
 
 static int kvm_handle_halt(X86CPU *cpu)
 {
+    CPUState *cs = CPU(cpu);
     CPUX86State *env = &cpu->env;
 
-    if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+    if (!((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
           (env->eflags & IF_MASK)) &&
-        !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
-        env->halted = 1;
+        !(cs->interrupt_request & CPU_INTERRUPT_NMI)) {
+        cs->halted = 1;
         return EXCP_HLT;
     }
 
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 8df6a6b645..b80a5f4470 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -171,14 +171,16 @@ static const VMStateInfo vmstate_fpreg_1_no_mmx = {
 
 static bool fpregs_is_0(void *opaque, int version_id)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
 
     return (env->fpregs_format_vmstate == 0);
 }
 
 static bool fpregs_is_1_mmx(void *opaque, int version_id)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
     int guess_mmx;
 
     guess_mmx = ((env->fptag_vmstate == 0xff) &&
@@ -188,7 +190,8 @@ static bool fpregs_is_1_mmx(void *opaque, int version_id)
 
 static bool fpregs_is_1_no_mmx(void *opaque, int version_id)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
     int guess_mmx;
 
     guess_mmx = ((env->fptag_vmstate == 0xff) &&
@@ -237,7 +240,8 @@ static const VMStateInfo vmstate_hack_uint64_as_uint32 = {
 
 static void cpu_pre_save(void *opaque)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
     int i;
 
     /* FPU */
@@ -252,7 +256,8 @@ static void cpu_pre_save(void *opaque)
 
 static int cpu_post_load(void *opaque, int version_id)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
     int i;
 
     /* XXX: restore FPU round state */
@@ -275,16 +280,16 @@ static int cpu_post_load(void *opaque, int version_id)
 
 static bool async_pf_msr_needed(void *opaque)
 {
-    CPUX86State *cpu = opaque;
+    X86CPU *cpu = opaque;
 
-    return cpu->async_pf_en_msr != 0;
+    return cpu->env.async_pf_en_msr != 0;
 }
 
 static bool pv_eoi_msr_needed(void *opaque)
 {
-    CPUX86State *cpu = opaque;
+    X86CPU *cpu = opaque;
 
-    return cpu->pv_eoi_en_msr != 0;
+    return cpu->env.pv_eoi_en_msr != 0;
 }
 
 static const VMStateDescription vmstate_async_pf_msr = {
@@ -293,7 +298,7 @@ static const VMStateDescription vmstate_async_pf_msr = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT64(async_pf_en_msr, CPUX86State),
+        VMSTATE_UINT64(env.async_pf_en_msr, X86CPU),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -304,14 +309,15 @@ static const VMStateDescription vmstate_pv_eoi_msr = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT64(pv_eoi_en_msr, CPUX86State),
+        VMSTATE_UINT64(env.pv_eoi_en_msr, X86CPU),
         VMSTATE_END_OF_LIST()
     }
 };
 
 static bool fpop_ip_dp_needed(void *opaque)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
 
     return env->fpop != 0 || env->fpip != 0 || env->fpdp != 0;
 }
@@ -322,16 +328,17 @@ static const VMStateDescription vmstate_fpop_ip_dp = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT16(fpop, CPUX86State),
-        VMSTATE_UINT64(fpip, CPUX86State),
-        VMSTATE_UINT64(fpdp, CPUX86State),
+        VMSTATE_UINT16(env.fpop, X86CPU),
+        VMSTATE_UINT64(env.fpip, X86CPU),
+        VMSTATE_UINT64(env.fpdp, X86CPU),
         VMSTATE_END_OF_LIST()
     }
 };
 
 static bool tsc_adjust_needed(void *opaque)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
 
     return env->tsc_adjust != 0;
 }
@@ -342,14 +349,15 @@ static const VMStateDescription vmstate_msr_tsc_adjust = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
-        VMSTATE_UINT64(tsc_adjust, CPUX86State),
+        VMSTATE_UINT64(env.tsc_adjust, X86CPU),
         VMSTATE_END_OF_LIST()
     }
 };
 
 static bool tscdeadline_needed(void *opaque)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
 
     return env->tsc_deadline != 0;
 }
@@ -360,14 +368,15 @@ static const VMStateDescription vmstate_msr_tscdeadline = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT64(tsc_deadline, CPUX86State),
+        VMSTATE_UINT64(env.tsc_deadline, X86CPU),
         VMSTATE_END_OF_LIST()
     }
 };
 
 static bool misc_enable_needed(void *opaque)
 {
-    CPUX86State *env = opaque;
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
 
     return env->msr_ia32_misc_enable != MSR_IA32_MISC_ENABLE_DEFAULT;
 }
@@ -378,111 +387,111 @@ static const VMStateDescription vmstate_msr_ia32_misc_enable = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT64(msr_ia32_misc_enable, CPUX86State),
+        VMSTATE_UINT64(env.msr_ia32_misc_enable, X86CPU),
         VMSTATE_END_OF_LIST()
     }
 };
 
-static const VMStateDescription vmstate_cpu = {
+const VMStateDescription vmstate_x86_cpu = {
     .name = "cpu",
-    .version_id = CPU_SAVE_VERSION,
+    .version_id = 12,
     .minimum_version_id = 3,
     .minimum_version_id_old = 3,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields      = (VMStateField []) {
-        VMSTATE_UINTTL_ARRAY(regs, CPUX86State, CPU_NB_REGS),
-        VMSTATE_UINTTL(eip, CPUX86State),
-        VMSTATE_UINTTL(eflags, CPUX86State),
-        VMSTATE_UINT32(hflags, CPUX86State),
+        VMSTATE_UINTTL_ARRAY(env.regs, X86CPU, CPU_NB_REGS),
+        VMSTATE_UINTTL(env.eip, X86CPU),
+        VMSTATE_UINTTL(env.eflags, X86CPU),
+        VMSTATE_UINT32(env.hflags, X86CPU),
         /* FPU */
-        VMSTATE_UINT16(fpuc, CPUX86State),
-        VMSTATE_UINT16(fpus_vmstate, CPUX86State),
-        VMSTATE_UINT16(fptag_vmstate, CPUX86State),
-        VMSTATE_UINT16(fpregs_format_vmstate, CPUX86State),
-        VMSTATE_FP_REGS(fpregs, CPUX86State, 8),
-
-        VMSTATE_SEGMENT_ARRAY(segs, CPUX86State, 6),
-        VMSTATE_SEGMENT(ldt, CPUX86State),
-        VMSTATE_SEGMENT(tr, CPUX86State),
-        VMSTATE_SEGMENT(gdt, CPUX86State),
-        VMSTATE_SEGMENT(idt, CPUX86State),
-
-        VMSTATE_UINT32(sysenter_cs, CPUX86State),
+        VMSTATE_UINT16(env.fpuc, X86CPU),
+        VMSTATE_UINT16(env.fpus_vmstate, X86CPU),
+        VMSTATE_UINT16(env.fptag_vmstate, X86CPU),
+        VMSTATE_UINT16(env.fpregs_format_vmstate, X86CPU),
+        VMSTATE_FP_REGS(env.fpregs, X86CPU, 8),
+
+        VMSTATE_SEGMENT_ARRAY(env.segs, X86CPU, 6),
+        VMSTATE_SEGMENT(env.ldt, X86CPU),
+        VMSTATE_SEGMENT(env.tr, X86CPU),
+        VMSTATE_SEGMENT(env.gdt, X86CPU),
+        VMSTATE_SEGMENT(env.idt, X86CPU),
+
+        VMSTATE_UINT32(env.sysenter_cs, X86CPU),
 #ifdef TARGET_X86_64
         /* Hack: In v7 size changed from 32 to 64 bits on x86_64 */
-        VMSTATE_HACK_UINT32(sysenter_esp, CPUX86State, less_than_7),
-        VMSTATE_HACK_UINT32(sysenter_eip, CPUX86State, less_than_7),
-        VMSTATE_UINTTL_V(sysenter_esp, CPUX86State, 7),
-        VMSTATE_UINTTL_V(sysenter_eip, CPUX86State, 7),
+        VMSTATE_HACK_UINT32(env.sysenter_esp, X86CPU, less_than_7),
+        VMSTATE_HACK_UINT32(env.sysenter_eip, X86CPU, less_than_7),
+        VMSTATE_UINTTL_V(env.sysenter_esp, X86CPU, 7),
+        VMSTATE_UINTTL_V(env.sysenter_eip, X86CPU, 7),
 #else
-        VMSTATE_UINTTL(sysenter_esp, CPUX86State),
-        VMSTATE_UINTTL(sysenter_eip, CPUX86State),
+        VMSTATE_UINTTL(env.sysenter_esp, X86CPU),
+        VMSTATE_UINTTL(env.sysenter_eip, X86CPU),
 #endif
 
-        VMSTATE_UINTTL(cr[0], CPUX86State),
-        VMSTATE_UINTTL(cr[2], CPUX86State),
-        VMSTATE_UINTTL(cr[3], CPUX86State),
-        VMSTATE_UINTTL(cr[4], CPUX86State),
-        VMSTATE_UINTTL_ARRAY(dr, CPUX86State, 8),
+        VMSTATE_UINTTL(env.cr[0], X86CPU),
+        VMSTATE_UINTTL(env.cr[2], X86CPU),
+        VMSTATE_UINTTL(env.cr[3], X86CPU),
+        VMSTATE_UINTTL(env.cr[4], X86CPU),
+        VMSTATE_UINTTL_ARRAY(env.dr, X86CPU, 8),
         /* MMU */
-        VMSTATE_INT32(a20_mask, CPUX86State),
+        VMSTATE_INT32(env.a20_mask, X86CPU),
         /* XMM */
-        VMSTATE_UINT32(mxcsr, CPUX86State),
-        VMSTATE_XMM_REGS(xmm_regs, CPUX86State, CPU_NB_REGS),
+        VMSTATE_UINT32(env.mxcsr, X86CPU),
+        VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, CPU_NB_REGS),
 
 #ifdef TARGET_X86_64
-        VMSTATE_UINT64(efer, CPUX86State),
-        VMSTATE_UINT64(star, CPUX86State),
-        VMSTATE_UINT64(lstar, CPUX86State),
-        VMSTATE_UINT64(cstar, CPUX86State),
-        VMSTATE_UINT64(fmask, CPUX86State),
-        VMSTATE_UINT64(kernelgsbase, CPUX86State),
+        VMSTATE_UINT64(env.efer, X86CPU),
+        VMSTATE_UINT64(env.star, X86CPU),
+        VMSTATE_UINT64(env.lstar, X86CPU),
+        VMSTATE_UINT64(env.cstar, X86CPU),
+        VMSTATE_UINT64(env.fmask, X86CPU),
+        VMSTATE_UINT64(env.kernelgsbase, X86CPU),
 #endif
-        VMSTATE_UINT32_V(smbase, CPUX86State, 4),
-
-        VMSTATE_UINT64_V(pat, CPUX86State, 5),
-        VMSTATE_UINT32_V(hflags2, CPUX86State, 5),
-
-        VMSTATE_UINT32_TEST(halted, CPUX86State, version_is_5),
-        VMSTATE_UINT64_V(vm_hsave, CPUX86State, 5),
-        VMSTATE_UINT64_V(vm_vmcb, CPUX86State, 5),
-        VMSTATE_UINT64_V(tsc_offset, CPUX86State, 5),
-        VMSTATE_UINT64_V(intercept, CPUX86State, 5),
-        VMSTATE_UINT16_V(intercept_cr_read, CPUX86State, 5),
-        VMSTATE_UINT16_V(intercept_cr_write, CPUX86State, 5),
-        VMSTATE_UINT16_V(intercept_dr_read, CPUX86State, 5),
-        VMSTATE_UINT16_V(intercept_dr_write, CPUX86State, 5),
-        VMSTATE_UINT32_V(intercept_exceptions, CPUX86State, 5),
-        VMSTATE_UINT8_V(v_tpr, CPUX86State, 5),
+        VMSTATE_UINT32_V(env.smbase, X86CPU, 4),
+
+        VMSTATE_UINT64_V(env.pat, X86CPU, 5),
+        VMSTATE_UINT32_V(env.hflags2, X86CPU, 5),
+
+        VMSTATE_UINT32_TEST(parent_obj.halted, X86CPU, version_is_5),
+        VMSTATE_UINT64_V(env.vm_hsave, X86CPU, 5),
+        VMSTATE_UINT64_V(env.vm_vmcb, X86CPU, 5),
+        VMSTATE_UINT64_V(env.tsc_offset, X86CPU, 5),
+        VMSTATE_UINT64_V(env.intercept, X86CPU, 5),
+        VMSTATE_UINT16_V(env.intercept_cr_read, X86CPU, 5),
+        VMSTATE_UINT16_V(env.intercept_cr_write, X86CPU, 5),
+        VMSTATE_UINT16_V(env.intercept_dr_read, X86CPU, 5),
+        VMSTATE_UINT16_V(env.intercept_dr_write, X86CPU, 5),
+        VMSTATE_UINT32_V(env.intercept_exceptions, X86CPU, 5),
+        VMSTATE_UINT8_V(env.v_tpr, X86CPU, 5),
         /* MTRRs */
-        VMSTATE_UINT64_ARRAY_V(mtrr_fixed, CPUX86State, 11, 8),
-        VMSTATE_UINT64_V(mtrr_deftype, CPUX86State, 8),
-        VMSTATE_MTRR_VARS(mtrr_var, CPUX86State, 8, 8),
+        VMSTATE_UINT64_ARRAY_V(env.mtrr_fixed, X86CPU, 11, 8),
+        VMSTATE_UINT64_V(env.mtrr_deftype, X86CPU, 8),
+        VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, 8, 8),
         /* KVM-related states */
-        VMSTATE_INT32_V(interrupt_injected, CPUX86State, 9),
-        VMSTATE_UINT32_V(mp_state, CPUX86State, 9),
-        VMSTATE_UINT64_V(tsc, CPUX86State, 9),
-        VMSTATE_INT32_V(exception_injected, CPUX86State, 11),
-        VMSTATE_UINT8_V(soft_interrupt, CPUX86State, 11),
-        VMSTATE_UINT8_V(nmi_injected, CPUX86State, 11),
-        VMSTATE_UINT8_V(nmi_pending, CPUX86State, 11),
-        VMSTATE_UINT8_V(has_error_code, CPUX86State, 11),
-        VMSTATE_UINT32_V(sipi_vector, CPUX86State, 11),
+        VMSTATE_INT32_V(env.interrupt_injected, X86CPU, 9),
+        VMSTATE_UINT32_V(env.mp_state, X86CPU, 9),
+        VMSTATE_UINT64_V(env.tsc, X86CPU, 9),
+        VMSTATE_INT32_V(env.exception_injected, X86CPU, 11),
+        VMSTATE_UINT8_V(env.soft_interrupt, X86CPU, 11),
+        VMSTATE_UINT8_V(env.nmi_injected, X86CPU, 11),
+        VMSTATE_UINT8_V(env.nmi_pending, X86CPU, 11),
+        VMSTATE_UINT8_V(env.has_error_code, X86CPU, 11),
+        VMSTATE_UINT32_V(env.sipi_vector, X86CPU, 11),
         /* MCE */
-        VMSTATE_UINT64_V(mcg_cap, CPUX86State, 10),
-        VMSTATE_UINT64_V(mcg_status, CPUX86State, 10),
-        VMSTATE_UINT64_V(mcg_ctl, CPUX86State, 10),
-        VMSTATE_UINT64_ARRAY_V(mce_banks, CPUX86State, MCE_BANKS_DEF *4, 10),
+        VMSTATE_UINT64_V(env.mcg_cap, X86CPU, 10),
+        VMSTATE_UINT64_V(env.mcg_status, X86CPU, 10),
+        VMSTATE_UINT64_V(env.mcg_ctl, X86CPU, 10),
+        VMSTATE_UINT64_ARRAY_V(env.mce_banks, X86CPU, MCE_BANKS_DEF * 4, 10),
         /* rdtscp */
-        VMSTATE_UINT64_V(tsc_aux, CPUX86State, 11),
+        VMSTATE_UINT64_V(env.tsc_aux, X86CPU, 11),
         /* KVM pvclock msr */
-        VMSTATE_UINT64_V(system_time_msr, CPUX86State, 11),
-        VMSTATE_UINT64_V(wall_clock_msr, CPUX86State, 11),
+        VMSTATE_UINT64_V(env.system_time_msr, X86CPU, 11),
+        VMSTATE_UINT64_V(env.wall_clock_msr, X86CPU, 11),
         /* XSAVE related fields */
-        VMSTATE_UINT64_V(xcr0, CPUX86State, 12),
-        VMSTATE_UINT64_V(xstate_bv, CPUX86State, 12),
-        VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUX86State, CPU_NB_REGS, 12),
+        VMSTATE_UINT64_V(env.xcr0, X86CPU, 12),
+        VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12),
+        VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, CPU_NB_REGS, 12),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
     },
@@ -510,13 +519,3 @@ static const VMStateDescription vmstate_cpu = {
         }
     }
 };
-
-void cpu_save(QEMUFile *f, void *opaque)
-{
-    vmstate_save_state(f, &vmstate_cpu, opaque);
-}
-
-int cpu_load(QEMUFile *f, void *opaque, int version_id)
-{
-    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
-}
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index b6d574019a..dfbc07b7f8 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -553,20 +553,25 @@ void helper_rdmsr(CPUX86State *env)
 }
 #endif
 
-static void do_hlt(CPUX86State *env)
+static void do_hlt(X86CPU *cpu)
 {
+    CPUState *cs = CPU(cpu);
+    CPUX86State *env = &cpu->env;
+
     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
-    env->halted = 1;
+    cs->halted = 1;
     env->exception_index = EXCP_HLT;
     cpu_loop_exit(env);
 }
 
 void helper_hlt(CPUX86State *env, int next_eip_addend)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
+
     cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0);
     EIP += next_eip_addend;
 
-    do_hlt(env);
+    do_hlt(cpu);
 }
 
 void helper_monitor(CPUX86State *env, target_ulong ptr)
@@ -580,7 +585,8 @@ void helper_monitor(CPUX86State *env, target_ulong ptr)
 
 void helper_mwait(CPUX86State *env, int next_eip_addend)
 {
-    CPUState *cpu;
+    CPUState *cs;
+    X86CPU *cpu;
 
     if ((uint32_t)ECX != 0) {
         raise_exception(env, EXCP0D_GPF);
@@ -588,13 +594,14 @@ void helper_mwait(CPUX86State *env, int next_eip_addend)
     cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0);
     EIP += next_eip_addend;
 
-    cpu = CPU(x86_env_get_cpu(env));
+    cpu = x86_env_get_cpu(env);
+    cs = CPU(cpu);
     /* XXX: not complete but not completely erroneous */
-    if (cpu->cpu_index != 0 || env->next_cpu != NULL) {
+    if (cs->cpu_index != 0 || env->next_cpu != NULL) {
         /* more than one CPU: do not sleep because another CPU may
            wake this one */
     } else {
-        do_hlt(env);
+        do_hlt(cpu);
     }
 }
 
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 3247deeb60..906e4f3d20 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -1231,8 +1231,11 @@ static void do_interrupt_all(CPUX86State *env, int intno, int is_int,
 #endif
 }
 
-void do_interrupt(CPUX86State *env)
+void x86_cpu_do_interrupt(CPUState *cs)
 {
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
 #if defined(CONFIG_USER_ONLY)
     /* if user mode only, we simulate a fake exception
        which will be handled outside the cpu execution
diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c
index 3f246e9073..c46a213c9c 100644
--- a/target-i386/svm_helper.c
+++ b/target-i386/svm_helper.c
@@ -271,7 +271,9 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
     env->hflags2 |= HF2_GIF_MASK;
 
     if (int_ctl & V_IRQ_MASK) {
-        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
+        CPUState *cs = CPU(x86_env_get_cpu(env));
+
+        cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
     }
 
     /* maybe we need to inject an event */
@@ -548,6 +550,7 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
 /* Note: currently only 32 bits of exit_code are used */
 void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     uint32_t int_ctl;
 
     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
@@ -594,7 +597,7 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
     int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
     int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
     int_ctl |= env->v_tpr & V_TPR_MASK;
-    if (env->interrupt_request & CPU_INTERRUPT_VIRQ) {
+    if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
         int_ctl |= V_IRQ_MASK;
     }
     stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
@@ -615,7 +618,7 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
     env->hflags &= ~HF_SVMI_MASK;
     env->intercept = 0;
     env->intercept_exceptions = 0;
-    env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+    cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
     env->tsc_offset = 0;
 
     env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb,
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
index c0b6ce5897..957186075b 100644
--- a/target-lm32/cpu-qom.h
+++ b/target-lm32/cpu-qom.h
@@ -71,4 +71,10 @@ static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env)
 
 #define ENV_OFFSET offsetof(LM32CPU, env)
 
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vmstate_lm32_cpu;
+#endif
+
+void lm32_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index a2badb5701..bbb7fbf768 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -83,6 +83,9 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
 
     lcc->parent_reset = cc->reset;
     cc->reset = lm32_cpu_reset;
+
+    cc->do_interrupt = lm32_cpu_do_interrupt;
+    cpu_class_set_vmsd(cc, &vmstate_lm32_cpu);
 }
 
 static const TypeInfo lm32_cpu_type_info = {
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index 6948d0e248..fd50b534fc 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -189,7 +189,6 @@ struct CPULM32State {
 LM32CPU *cpu_lm32_init(const char *cpu_model);
 void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf);
 int cpu_lm32_exec(CPULM32State *s);
-void do_interrupt(CPULM32State *env);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
@@ -212,8 +211,6 @@ static inline CPULM32State *cpu_init(const char *cpu_model)
 #define cpu_gen_code cpu_lm32_gen_code
 #define cpu_signal_handler cpu_lm32_signal_handler
 
-#define CPU_SAVE_VERSION 1
-
 int cpu_lm32_handle_mmu_fault(CPULM32State *env, target_ulong address, int rw,
                               int mmu_idx);
 #define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault
@@ -254,9 +251,7 @@ static inline void cpu_get_tb_cpu_state(CPULM32State *env, target_ulong *pc,
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPULM32State *env = &LM32_CPU(cpu)->env;
-
-    return env->interrupt_request & CPU_INTERRUPT_HARD;
+    return cpu->interrupt_request & CPU_INTERRUPT_HARD;
 }
 
 #include "exec/exec-all.h"
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 47ae7e775a..a0a8399906 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -42,8 +42,11 @@ hwaddr cpu_get_phys_page_debug(CPULM32State *env, target_ulong addr)
     return addr & TARGET_PAGE_MASK;
 }
 
-void do_interrupt(CPULM32State *env)
+void lm32_cpu_do_interrupt(CPUState *cs)
 {
+    LM32CPU *cpu = LM32_CPU(cs);
+    CPULM32State *env = &cpu->env;
+
     qemu_log_mask(CPU_LOG_INT,
             "exception at pc=%x type=%x\n", env->pc, env->exception_index);
 
diff --git a/target-lm32/machine.c b/target-lm32/machine.c
index 6802e818f8..9e0919c254 100644
--- a/target-lm32/machine.c
+++ b/target-lm32/machine.c
@@ -1,9 +1,9 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
 
-static const VMStateDescription vmstate_cpu = {
-    .name = "cpu",
-    .version_id = CPU_SAVE_VERSION,
+static const VMStateDescription vmstate_env = {
+    .name = "env",
+    .version_id = 1,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
@@ -22,12 +22,13 @@ static const VMStateDescription vmstate_cpu = {
     }
 };
 
-void cpu_save(QEMUFile *f, void *opaque)
-{
-    vmstate_save_state(f, &vmstate_cpu, opaque);
-}
-
-int cpu_load(QEMUFile *f, void *opaque, int version_id)
-{
-    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
-}
+const VMStateDescription vmstate_lm32_cpu = {
+    .name = "cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT(env, LM32CPU, 1, vmstate_env, CPULM32State),
+        VMSTATE_END_OF_LIST()
+    }
+};
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index 53410b176e..ebc94a0681 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -25,7 +25,9 @@ void helper_raise_exception(CPULM32State *env, uint32_t index)
 
 void helper_hlt(CPULM32State *env)
 {
-    env->halted = 1;
+    CPUState *cs = CPU(lm32_env_get_cpu(env));
+
+    cs->halted = 1;
     env->exception_index = EXCP_HLT;
     cpu_loop_exit(env);
 }
diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h
index f4c33b2eb3..846aa7453e 100644
--- a/target-m68k/cpu-qom.h
+++ b/target-m68k/cpu-qom.h
@@ -70,4 +70,6 @@ static inline M68kCPU *m68k_env_get_cpu(CPUM68KState *env)
 
 #define ENV_OFFSET offsetof(M68kCPU, env)
 
+void m68k_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c
index f5a109854b..3c65b4e44f 100644
--- a/target-m68k/cpu.c
+++ b/target-m68k/cpu.c
@@ -186,6 +186,7 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
     cc->reset = m68k_cpu_reset;
 
     cc->class_by_name = m68k_cpu_class_by_name;
+    cc->do_interrupt = m68k_cpu_do_interrupt;
     dc->vmsd = &vmstate_m68k_cpu;
 }
 
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 2672eae7c8..c90c40c370 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -119,7 +119,6 @@ void m68k_tcg_init(void);
 void m68k_cpu_init_gdb(M68kCPU *cpu);
 M68kCPU *cpu_m68k_init(const char *cpu_model);
 int cpu_m68k_exec(CPUM68KState *s);
-void do_interrupt(CPUM68KState *env1);
 void do_interrupt_m68k_hardirq(CPUM68KState *env1);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
@@ -265,9 +264,7 @@ static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc,
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUM68KState *env = &M68K_CPU(cpu)->env;
-
-    return env->interrupt_request & CPU_INTERRUPT_HARD;
+    return cpu->interrupt_request & CPU_INTERRUPT_HARD;
 }
 
 #include "exec/exec-all.h"
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 1bae3ab326..54fa419ace 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -312,14 +312,16 @@ int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw,
    simplicitly we calculate it when the interrupt is signalled.  */
 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
 {
+    CPUState *cs = CPU(cpu);
     CPUM68KState *env = &cpu->env;
 
     env->pending_level = level;
     env->pending_vector = vector;
-    if (level)
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    else
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    if (level) {
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+    }
 }
 
 #endif
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index 16df24c0ca..30f7d8b1ab 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -21,8 +21,11 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt(CPUM68KState *env)
+void m68k_cpu_do_interrupt(CPUState *cs)
 {
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
     env->exception_index = -1;
 }
 
@@ -84,6 +87,7 @@ static void do_rte(CPUM68KState *env)
 
 static void do_interrupt_all(CPUM68KState *env, int is_hw)
 {
+    CPUState *cs;
     uint32_t sp;
     uint32_t fmt;
     uint32_t retaddr;
@@ -108,7 +112,8 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
                 do_m68k_semihosting(env, env->dregs[0]);
                 return;
             }
-            env->halted = 1;
+            cs = CPU(m68k_env_get_cpu(env));
+            cs->halted = 1;
             env->exception_index = EXCP_HLT;
             cpu_loop_exit(env);
             return;
@@ -147,8 +152,11 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
     env->pc = cpu_ldl_kernel(env, env->vbr + vector);
 }
 
-void do_interrupt(CPUM68KState *env)
+void m68k_cpu_do_interrupt(CPUState *cs)
 {
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
     do_interrupt_all(env, 0);
 }
 
diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def
index 49400c4475..4235b02764 100644
--- a/target-m68k/qregs.def
+++ b/target-m68k/qregs.def
@@ -8,6 +8,5 @@ DEFO32(CC_X, cc_x)
 DEFO32(DIV1, div1)
 DEFO32(DIV2, div2)
 DEFO32(EXCEPTION, exception_index)
-DEFO32(HALTED, halted)
 DEFO32(MACSR, macsr)
 DEFO32(MAC_MASK, mac_mask)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 20a86d8efe..32b8132da6 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -42,6 +42,8 @@
 #undef DEFO64
 #undef DEFF64
 
+static TCGv_i32 cpu_halted;
+
 static TCGv_ptr cpu_env;
 
 static char cpu_reg_names[3*8*3 + 5*4];
@@ -76,6 +78,10 @@ void m68k_tcg_init(void)
 #undef DEFO64
 #undef DEFF64
 
+    cpu_halted = tcg_global_mem_new_i32(TCG_AREG0,
+                                        -offsetof(M68kCPU, env) +
+                                        offsetof(CPUState, halted), "HALTED");
+
     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
 
     p = cpu_reg_names;
@@ -2024,7 +2030,7 @@ DISAS_INSN(stop)
     s->pc += 2;
 
     gen_set_sr_im(s, ext, 0);
-    tcg_gen_movi_i32(QREG_HALTED, 1);
+    tcg_gen_movi_i32(cpu_halted, 1);
     gen_exception(s, s->pc, EXCP_HLT);
 }
 
diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h
index a0248a5a22..aa51cf6406 100644
--- a/target-microblaze/cpu-qom.h
+++ b/target-microblaze/cpu-qom.h
@@ -70,4 +70,6 @@ static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env)
 
 #define ENV_OFFSET offsetof(MicroBlazeCPU, env)
 
+void mb_cpu_do_interrupt(CPUState *cs);
+
 #endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 81359db168..0f4293dbd5 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -131,6 +131,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
     mcc->parent_reset = cc->reset;
     cc->reset = mb_cpu_reset;
 
+    cc->do_interrupt = mb_cpu_do_interrupt;
     dc->vmsd = &vmstate_mb_cpu;
 }
 
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index c3dd7f6219..1813939fc9 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -275,7 +275,6 @@ struct CPUMBState {
 void mb_tcg_init(void);
 MicroBlazeCPU *cpu_mb_init(const char *cpu_model);
 int cpu_mb_exec(CPUMBState *s);
-void do_interrupt(CPUMBState *env);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
@@ -374,9 +373,7 @@ void cpu_unassigned_access(CPUMBState *env1, hwaddr addr,
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUMBState *env = &MICROBLAZE_CPU(cpu)->env;
-
-    return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+    return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
 }
 
 #include "exec/exec-all.h"
diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c
index 97aedc52bb..a0416d0b72 100644
--- a/target-microblaze/helper.c
+++ b/target-microblaze/helper.c
@@ -26,8 +26,11 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUMBState *env)
+void mb_cpu_do_interrupt(CPUState *cs)
 {
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUMBState *env = &cpu->env;
+
     env->exception_index = -1;
     env->res_addr = RES_ADDR_NONE;
     env->regs[14] = env->sregs[SR_PC];
@@ -109,8 +112,10 @@ int cpu_mb_handle_mmu_fault (CPUMBState *env, target_ulong address, int rw,
     return r;
 }
 
-void do_interrupt(CPUMBState *env)
+void mb_cpu_do_interrupt(CPUState *cs)
 {
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUMBState *env = &cpu->env;
     uint32_t t;
 
     /* IMM flag cannot propagate across a branch and into the dslot.  */
diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h
index c6bcddfb9a..32e3cad7bf 100644
--- a/target-mips/cpu-qom.h
+++ b/target-mips/cpu-qom.h
@@ -74,4 +74,6 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env)
 
 #define ENV_OFFSET offsetof(MIPSCPU, env)
 
+void mips_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 4d62031c36..5315f7bda0 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -78,6 +78,8 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
 
     mcc->parent_reset = cc->reset;
     cc->reset = mips_cpu_reset;
+
+    cc->do_interrupt = mips_cpu_do_interrupt;
 }
 
 static const TypeInfo mips_cpu_type_info = {
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index ca63148b18..cedf03df43 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -663,7 +663,6 @@ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level);
 int cpu_mips_handle_mmu_fault (CPUMIPSState *env, target_ulong address, int rw,
                                int mmu_idx);
 #define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
-void do_interrupt (CPUMIPSState *env);
 #if !defined(CONFIG_USER_ONLY)
 void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra);
 hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address,
@@ -722,7 +721,7 @@ static inline bool cpu_has_work(CPUState *cpu)
     /* It is implementation dependent if non-enabled interrupts
        wake-up the CPU, however most of the implementations only
        check for interrupts that can be taken. */
-    if ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+    if ((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
         cpu_mips_hw_interrupts_pending(env)) {
         has_work = true;
     }
@@ -731,7 +730,7 @@ static inline bool cpu_has_work(CPUState *cpu)
     if (env->CP0_Config3 & (1 << CP0C3_MT)) {
         /* The QEMU model will issue an _WAKE request whenever the CPUs
            should be woken up.  */
-        if (env->interrupt_request & CPU_INTERRUPT_WAKE) {
+        if (cpu->interrupt_request & CPU_INTERRUPT_WAKE) {
             has_work = true;
         }
 
diff --git a/target-mips/helper.c b/target-mips/helper.c
index e877b8db78..3a54acf706 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -396,10 +396,11 @@ static void set_hflags_for_handler (CPUMIPSState *env)
 }
 #endif
 
-void do_interrupt (CPUMIPSState *env)
+void mips_cpu_do_interrupt(CPUState *cs)
 {
+    MIPSCPU *cpu = MIPS_CPU(cs);
+    CPUMIPSState *env = &cpu->env;
 #if !defined(CONFIG_USER_ONLY)
-    MIPSCPU *cpu = mips_env_get_cpu(env);
     target_ulong offset;
     int cause = -1;
     const char *name;
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 45cbb2f1c2..3fa0d00cf9 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -515,29 +515,30 @@ void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 /* SMP helpers.  */
 static bool mips_vpe_is_wfi(MIPSCPU *c)
 {
+    CPUState *cpu = CPU(c);
     CPUMIPSState *env = &c->env;
 
     /* If the VPE is halted but otherwise active, it means it's waiting for
        an interrupt.  */
-    return env->halted && mips_vpe_active(env);
+    return cpu->halted && mips_vpe_active(env);
 }
 
-static inline void mips_vpe_wake(CPUMIPSState *c)
+static inline void mips_vpe_wake(MIPSCPU *c)
 {
     /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
        because there might be other conditions that state that c should
        be sleeping.  */
-    cpu_interrupt(c, CPU_INTERRUPT_WAKE);
+    cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
 }
 
 static inline void mips_vpe_sleep(MIPSCPU *cpu)
 {
-    CPUMIPSState *c = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
     /* The VPE was shut off, really go to bed.
        Reset any old _WAKE requests.  */
-    c->halted = 1;
-    cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE);
+    cs->halted = 1;
+    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
 }
 
 static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
@@ -546,7 +547,7 @@ static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
 
     /* FIXME: TC reschedule.  */
     if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
-        mips_vpe_wake(c);
+        mips_vpe_wake(cpu);
     }
 }
 
@@ -1724,7 +1725,7 @@ target_ulong helper_evpe(CPUMIPSState *env)
             && !mips_vpe_is_wfi(other_cpu)) {
             /* Enable the VPE.  */
             other_cpu_env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
-            mips_vpe_wake(other_cpu_env); /* And wake it up.  */
+            mips_vpe_wake(other_cpu); /* And wake it up.  */
         }
         other_cpu_env = other_cpu_env->next_cpu;
     } while (other_cpu_env);
@@ -2099,8 +2100,10 @@ void helper_pmon(CPUMIPSState *env, int function)
 
 void helper_wait(CPUMIPSState *env)
 {
-    env->halted = 1;
-    cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE);
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+
+    cs->halted = 1;
+    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
     helper_raise_exception(env, EXCP_HLT);
 }
 
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 694f07c49f..b7f8203e57 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -16004,7 +16004,7 @@ void cpu_state_reset(CPUMIPSState *env)
             env->tcs[i].CP0_TCHalt = 1;
         }
         env->active_tc.CP0_TCHalt = 1;
-        env->halted = 1;
+        cs->halted = 1;
 
         if (cs->cpu_index == 0) {
             /* VPE0 starts up enabled.  */
@@ -16012,7 +16012,7 @@ void cpu_state_reset(CPUMIPSState *env)
             env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
 
             /* TC0 starts up unhalted.  */
-            env->halted = 0;
+            cs->halted = 0;
             env->active_tc.CP0_TCHalt = 0;
             env->tcs[0].CP0_TCHalt = 0;
             /* With thread 0 active.  */
diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c
index 72d5e8d2a5..ffe14f3c8d 100644
--- a/target-openrisc/cpu.c
+++ b/target-openrisc/cpu.c
@@ -148,6 +148,7 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
     cc->reset = openrisc_cpu_reset;
 
     cc->class_by_name = openrisc_cpu_class_by_name;
+    cc->do_interrupt = openrisc_cpu_do_interrupt;
 }
 
 static void cpu_register(const OpenRISCCPUInfo *info)
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 4cfd1c74fb..b9c55ba83b 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -346,7 +346,7 @@ OpenRISCCPU *cpu_openrisc_init(const char *cpu_model);
 
 void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf);
 int cpu_openrisc_exec(CPUOpenRISCState *s);
-void do_interrupt(CPUOpenRISCState *env);
+void openrisc_cpu_do_interrupt(CPUState *cpu);
 void openrisc_translate_init(void);
 int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
                                   target_ulong address,
@@ -423,9 +423,7 @@ static inline int cpu_mmu_index(CPUOpenRISCState *env)
 #define CPU_INTERRUPT_TIMER   CPU_INTERRUPT_TGT_INT_0
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUOpenRISCState *env = &OPENRISC_CPU(cpu)->env;
-
-    return env->interrupt_request & (CPU_INTERRUPT_HARD |
+    return cpu->interrupt_request & (CPU_INTERRUPT_HARD |
                                      CPU_INTERRUPT_TIMER);
 }
 
diff --git a/target-openrisc/interrupt.c b/target-openrisc/interrupt.c
index 7f2c025da2..16ef4b3e79 100644
--- a/target-openrisc/interrupt.c
+++ b/target-openrisc/interrupt.c
@@ -25,8 +25,10 @@
 #include "hw/loader.h"
 #endif
 
-void do_interrupt(CPUOpenRISCState *env)
+void openrisc_cpu_do_interrupt(CPUState *cs)
 {
+    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+    CPUOpenRISCState *env = &cpu->env;
 #ifndef CONFIG_USER_ONLY
     if (env->flags & D_FLAG) { /* Delay Slot insn */
         env->flags &= ~D_FLAG;
diff --git a/target-openrisc/interrupt_helper.c b/target-openrisc/interrupt_helper.c
index a176441b01..844648f780 100644
--- a/target-openrisc/interrupt_helper.c
+++ b/target-openrisc/interrupt_helper.c
@@ -24,6 +24,7 @@
 void HELPER(rfe)(CPUOpenRISCState *env)
 {
     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
 #ifndef CONFIG_USER_ONLY
     int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^
                          (cpu->env.esr & (SR_SM | SR_IME | SR_DME));
@@ -53,5 +54,5 @@ void HELPER(rfe)(CPUOpenRISCState *env)
         tlb_flush(&cpu->env, 1);
     }
 #endif
-    cpu->env.interrupt_request |= CPU_INTERRUPT_EXITTB;
+    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
index 3c5f45ab75..cccbc0e939 100644
--- a/target-openrisc/sys_helper.c
+++ b/target-openrisc/sys_helper.c
@@ -31,6 +31,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
     int idx;
 
     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
 
     switch (spr) {
     case TO_SPR(0, 0): /* VR */
@@ -132,7 +133,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
                 env->ttmr = (rb & ~TTMR_IP) + ip;
             } else {    /* Clear IP bit.  */
                 env->ttmr = rb & ~TTMR_IP;
-                env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
+                cs->interrupt_request &= ~CPU_INTERRUPT_TIMER;
             }
 
             cpu_openrisc_count_update(cpu);
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 2bf0ab62d4..09bfae3d54 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -95,4 +95,6 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
 
 PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
 
+void ppc_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 417abb0dd1..6886666d6e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1133,7 +1133,6 @@ int cpu_ppc_signal_handler (int host_signum, void *pinfo,
 int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
                               int mmu_idx);
 #define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
-void do_interrupt (CPUPPCState *env);
 void ppc_hw_interrupt (CPUPPCState *env);
 
 #if !defined(CONFIG_USER_ONLY)
@@ -2217,9 +2216,10 @@ extern void (*cpu_ppc_hypercall)(PowerPCCPU *);
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUPPCState *env = &POWERPC_CPU(cpu)->env;
+    PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
+    CPUPPCState *env = &ppc_cpu->env;
 
-    return msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD);
+    return msr_ee && (cpu->interrupt_request & CPU_INTERRUPT_HARD);
 }
 
 #include "exec/exec-all.h"
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 0a1ac86a42..4a0fc6dd57 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -38,8 +38,11 @@ void (*cpu_ppc_hypercall)(PowerPCCPU *);
 /*****************************************************************************/
 /* Exception processing */
 #if defined(CONFIG_USER_ONLY)
-void do_interrupt(CPUPPCState *env)
+void ppc_cpu_do_interrupt(CPUState *cs)
 {
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
     env->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 }
@@ -66,6 +69,7 @@ static inline void dump_syscall(CPUPPCState *env)
 static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 {
     CPUPPCState *env = &cpu->env;
+    CPUState *cs;
     target_ulong msr, new_msr, vector;
     int srr0, srr1, asrr0, asrr1;
     int lpes0, lpes1, lev;
@@ -131,8 +135,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
                 fprintf(stderr, "Machine check while not allowed. "
                         "Entering checkstop state\n");
             }
-            env->halted = 1;
-            env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+            cs = CPU(cpu);
+            cs->halted = 1;
+            cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
         }
         if (0) {
             /* XXX: find a suitable condition to enable the hypervisor mode */
@@ -652,9 +657,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     }
 }
 
-void do_interrupt(CPUPPCState *env)
+void ppc_cpu_do_interrupt(CPUState *cs)
 {
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
 
     powerpc_excp(cpu, env->excp_model, env->exception_index);
 }
@@ -663,11 +669,12 @@ void ppc_hw_interrupt(CPUPPCState *env)
 {
     PowerPCCPU *cpu = ppc_env_get_cpu(env);
     int hdice;
-
 #if 0
+    CPUState *cs = CPU(cpu);
+
     qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
-                __func__, env, env->pending_interrupts,
-                env->interrupt_request, (int)msr_me, (int)msr_ee);
+                  __func__, env, env->pending_interrupts,
+                  cs->interrupt_request, (int)msr_me, (int)msr_ee);
 #endif
     /* External reset */
     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
@@ -807,9 +814,12 @@ void helper_raise_exception(CPUPPCState *env, uint32_t exception)
 #if !defined(CONFIG_USER_ONLY)
 void helper_store_msr(CPUPPCState *env, target_ulong val)
 {
+    CPUState *cs;
+
     val = hreg_store_msr(env, val, 0);
     if (val != 0) {
-        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+        cs = CPU(ppc_env_get_cpu(env));
+        cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
         helper_raise_exception(env, val);
     }
 }
@@ -817,6 +827,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
 static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
                           target_ulong msrm, int keep_msrh)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
 #if defined(TARGET_PPC64)
     if (msr_is_64bit(env, msr)) {
         nip = (uint64_t)nip;
@@ -841,7 +853,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
     /* No need to raise an exception here,
      * as rfi is always the last insn of a TB
      */
-    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 
 void helper_rfi(CPUPPCState *env)
@@ -983,7 +995,7 @@ void helper_msgsnd(target_ulong rb)
     for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
             cenv->pending_interrupts |= 1 << irq;
-            cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
+            cpu_interrupt(CPU(ppc_env_get_cpu(cenv)), CPU_INTERRUPT_HARD);
         }
     }
 }
diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h
index 3c988502ed..a6d5e2fe2f 100644
--- a/target-ppc/helper_regs.h
+++ b/target-ppc/helper_regs.h
@@ -68,10 +68,13 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
                                  int alter_hv)
 {
     int excp;
+#if !defined(CONFIG_USER_ONLY)
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+#endif
 
     excp = 0;
     value &= env->msr_mask;
-#if !defined (CONFIG_USER_ONLY)
+#if !defined(CONFIG_USER_ONLY)
     if (!alter_hv) {
         /* mtmsr cannot alter the hypervisor state */
         value &= ~MSR_HVB;
@@ -82,7 +85,7 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
         /* Flush all tlb when changing translation mode */
         tlb_flush(env, 1);
         excp = POWERPC_EXCP_NONE;
-        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+        cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
     }
     if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&
                  ((value ^ env->msr) & (1 << MSR_TGPR)))) {
@@ -96,10 +99,10 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
 #endif
     env->msr = value;
     hreg_compute_hflags(env);
-#if !defined (CONFIG_USER_ONLY)
+#if !defined(CONFIG_USER_ONLY)
     if (unlikely(msr_pow == 1)) {
         if ((*env->check_pow)(env)) {
-            env->halted = 1;
+            cs->halted = 1;
             excp = EXCP_HALTED;
         }
     }
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 9dff7607f1..e663ff0acb 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -993,7 +993,7 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
      * interrupt, reset, etc) in PPC-specific env->irq_input_state. */
     if (!cap_interrupt_level &&
         run->ready_for_interrupt_injection &&
-        (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
         (env->irq_input_state & (1<<PPC_INPUT_INT)))
     {
         /* For now KVM disregards the 'irq' argument. However, in the
@@ -1024,14 +1024,16 @@ void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run)
 
 int kvm_arch_process_async_events(CPUState *cs)
 {
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
-    return cpu->env.halted;
+    return cs->halted;
 }
 
-static int kvmppc_handle_halt(CPUPPCState *env)
+static int kvmppc_handle_halt(PowerPCCPU *cpu)
 {
-    if (!(env->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
-        env->halted = 1;
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
+        cs->halted = 1;
         env->exception_index = EXCP_HLT;
     }
 
@@ -1073,7 +1075,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
         break;
     case KVM_EXIT_HLT:
         dprintf("handle halt\n");
-        ret = kvmppc_handle_halt(env);
+        ret = kvmppc_handle_halt(cpu);
         break;
 #ifdef CONFIG_PSERIES
     case KVM_EXIT_PAPR_HCALL:
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index fa9e9e3857..380a884131 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -3103,7 +3103,8 @@ static void gen_sync(DisasContext *ctx)
 static void gen_wait(DisasContext *ctx)
 {
     TCGv_i32 t0 = tcg_temp_new_i32();
-    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, halted));
+    tcg_gen_st_i32(t0, cpu_env,
+                   -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
     tcg_temp_free_i32(t0);
     /* Stop translation, as the CPU is supposed to sleep from now */
     gen_exception_err(ctx, EXCP_HLT, 1);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 09ad4ba639..15eebe9177 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8427,6 +8427,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
     cc->reset = ppc_cpu_reset;
 
     cc->class_by_name = ppc_cpu_class_by_name;
+    cc->do_interrupt = ppc_cpu_do_interrupt;
 }
 
 static const TypeInfo ppc_cpu_type_info = {
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index f6e514570c..34d45c262b 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -71,4 +71,6 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env)
 
 #define ENV_OFFSET offsetof(S390CPU, env)
 
+void s390_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index b74654724d..23fe51f0f4 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -80,10 +80,10 @@ static void s390_cpu_reset(CPUState *s)
     env->cregs[0] = CR0_RESET;
     env->cregs[14] = CR14_RESET;
     /* set halted to 1 to make sure we can add the cpu in
-     * s390_ipl_cpu code, where env->halted is set back to 0
+     * s390_ipl_cpu code, where CPUState::halted is set back to 0
      * after incrementing the cpu counter */
 #if !defined(CONFIG_USER_ONLY)
-    env->halted = 1;
+    s->halted = 1;
 #endif
     tlb_flush(env, 1);
 }
@@ -129,10 +129,10 @@ static void s390_cpu_initfn(Object *obj)
     env->tod_basetime = 0;
     env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu);
     env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu);
-    /* set env->halted state to 1 to avoid decrementing the running
+    /* set CPUState::halted state to 1 to avoid decrementing the running
      * cpu counter in s390_cpu_reset to a negative number at
      * initial ipl */
-    env->halted = 1;
+    cs->halted = 1;
 #endif
     env->cpu_num = cpu_num++;
     env->ext_index = -1;
@@ -169,6 +169,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
     scc->parent_reset = cc->reset;
     cc->reset = s390_cpu_reset;
 
+    cc->do_interrupt = s390_cpu_do_interrupt;
     dc->vmsd = &vmstate_s390_cpu;
 }
 
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 9cb739da1e..e351005901 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -315,7 +315,6 @@ static inline int get_ilen(uint8_t opc)
 S390CPU *cpu_s390x_init(const char *cpu_model);
 void s390x_translate_init(void);
 int cpu_s390x_exec(CPUS390XState *s);
-void do_interrupt (CPUS390XState *env);
 
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
@@ -992,7 +991,7 @@ static inline void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param,
     env->ext_queue[env->ext_index].param64 = param64;
 
     env->pending_int |= INTERRUPT_EXT;
-    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 }
 
 static inline void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id,
@@ -1016,7 +1015,7 @@ static inline void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id,
     env->io_queue[env->io_index[isc]][isc].word = io_int_word;
 
     env->pending_int |= INTERRUPT_IO;
-    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 }
 
 static inline void cpu_inject_crw_mchk(S390CPU *cpu)
@@ -1034,14 +1033,15 @@ static inline void cpu_inject_crw_mchk(S390CPU *cpu)
     env->mchk_queue[env->mchk_index].type = 1;
 
     env->pending_int |= INTERRUPT_MCHK;
-    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 }
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUS390XState *env = &S390_CPU(cpu)->env;
+    S390CPU *s390_cpu = S390_CPU(cpu);
+    CPUS390XState *env = &s390_cpu->env;
 
-    return (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+    return (cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
         (env->psw.mask & PSW_MASK_EXT);
 }
 
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 1183b45ca1..b425054be8 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -57,7 +57,7 @@ void s390x_tod_timer(void *opaque)
     CPUS390XState *env = &cpu->env;
 
     env->pending_int |= INTERRUPT_TOD;
-    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 }
 
 void s390x_cpu_timer(void *opaque)
@@ -66,7 +66,7 @@ void s390x_cpu_timer(void *opaque)
     CPUS390XState *env = &cpu->env;
 
     env->pending_int |= INTERRUPT_CPUTIMER;
-    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 }
 #endif
 
@@ -86,8 +86,11 @@ S390CPU *cpu_s390x_init(const char *cpu_model)
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt(CPUS390XState *env)
+void s390_cpu_do_interrupt(CPUState *cs)
 {
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+
     env->exception_index = -1;
 }
 
@@ -437,6 +440,7 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
 {
     if (mask & PSW_MASK_WAIT) {
         S390CPU *cpu = s390_env_get_cpu(env);
+        CPUState *cs = CPU(cpu);
         if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) {
             if (s390_del_running_cpu(cpu) == 0) {
 #ifndef CONFIG_USER_ONLY
@@ -444,7 +448,7 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
 #endif
             }
         }
-        env->halted = 1;
+        cs->halted = 1;
         env->exception_index = EXCP_HLT;
     }
 
@@ -736,9 +740,10 @@ static void do_mchk_interrupt(CPUS390XState *env)
     load_psw(env, mask, addr);
 }
 
-void do_interrupt(CPUS390XState *env)
+void s390_cpu_do_interrupt(CPUState *cs)
 {
-    S390CPU *cpu = s390_env_get_cpu(env);
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
 
     qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n",
                   __func__, env->exception_index, env->psw.addr);
@@ -797,7 +802,7 @@ void do_interrupt(CPUS390XState *env)
     env->exception_index = -1;
 
     if (!env->pending_int) {
-        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+        cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
     }
 }
 
diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h
index f4e8976478..f8c80d30b4 100644
--- a/target-sh4/cpu-qom.h
+++ b/target-sh4/cpu-qom.h
@@ -24,6 +24,10 @@
 
 #define TYPE_SUPERH_CPU "superh-cpu"
 
+#define TYPE_SH7750R_CPU "sh7750r-" TYPE_SUPERH_CPU
+#define TYPE_SH7751R_CPU "sh7751r-" TYPE_SUPERH_CPU
+#define TYPE_SH7785_CPU "sh7785-" TYPE_SUPERH_CPU
+
 #define SUPERH_CPU_CLASS(klass) \
     OBJECT_CLASS_CHECK(SuperHCPUClass, (klass), TYPE_SUPERH_CPU)
 #define SUPERH_CPU(obj) \
@@ -35,6 +39,10 @@
  * SuperHCPUClass:
  * @parent_realize: The parent class' realize handler.
  * @parent_reset: The parent class' reset handler.
+ * @name: The name.
+ * @pvr: Processor Version Register
+ * @prr: Processor Revision Register
+ * @cvr: Cache Version Register
  *
  * A SuperH CPU model.
  */
@@ -45,6 +53,11 @@ typedef struct SuperHCPUClass {
 
     DeviceRealize parent_realize;
     void (*parent_reset)(CPUState *cpu);
+
+    const char *name;
+    uint32_t pvr;
+    uint32_t prr;
+    uint32_t cvr;
 } SuperHCPUClass;
 
 /**
@@ -70,4 +83,6 @@ static inline SuperHCPU *sh_env_get_cpu(CPUSH4State *env)
 
 #define ENV_OFFSET offsetof(SuperHCPU, env)
 
+void superh_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index ef0e62195d..898aecde4f 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -54,6 +54,180 @@ static void superh_cpu_reset(CPUState *s)
     set_default_nan_mode(1, &env->fp_status);
 }
 
+typedef struct SuperHCPUListState {
+    fprintf_function cpu_fprintf;
+    FILE *file;
+} SuperHCPUListState;
+
+/* Sort alphabetically by type name. */
+static gint superh_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+    ObjectClass *class_a = (ObjectClass *)a;
+    ObjectClass *class_b = (ObjectClass *)b;
+    const char *name_a, *name_b;
+
+    name_a = object_class_get_name(class_a);
+    name_b = object_class_get_name(class_b);
+    return strcmp(name_a, name_b);
+}
+
+static void superh_cpu_list_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+    SuperHCPUListState *s = user_data;
+
+    (*s->cpu_fprintf)(s->file, "%s\n",
+                      scc->name);
+}
+
+void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    SuperHCPUListState s = {
+        .cpu_fprintf = cpu_fprintf,
+        .file = f,
+    };
+    GSList *list;
+
+    list = object_class_get_list(TYPE_SUPERH_CPU, false);
+    list = g_slist_sort(list, superh_cpu_list_compare);
+    g_slist_foreach(list, superh_cpu_list_entry, &s);
+    g_slist_free(list);
+}
+
+static gint superh_cpu_name_compare(gconstpointer a, gconstpointer b)
+{
+    const SuperHCPUClass *scc = SUPERH_CPU_CLASS(a);
+    const char *name = b;
+
+    return strcasecmp(scc->name, name);
+}
+
+static ObjectClass *superh_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+    GSList *list, *item;
+
+    if (cpu_model == NULL) {
+        return NULL;
+    }
+    if (strcasecmp(cpu_model, "any") == 0) {
+        return object_class_by_name(TYPE_SH7750R_CPU);
+    }
+
+    oc = object_class_by_name(cpu_model);
+    if (oc != NULL && object_class_dynamic_cast(oc, TYPE_SUPERH_CPU) != NULL
+        && !object_class_is_abstract(oc)) {
+        return oc;
+    }
+
+    oc = NULL;
+    list = object_class_get_list(TYPE_SUPERH_CPU, false);
+    item = g_slist_find_custom(list, cpu_model, superh_cpu_name_compare);
+    if (item != NULL) {
+        oc = item->data;
+    }
+    g_slist_free(list);
+    return oc;
+}
+
+SuperHCPU *cpu_sh4_init(const char *cpu_model)
+{
+    SuperHCPU *cpu;
+    CPUSH4State *env;
+    ObjectClass *oc;
+
+    oc = superh_cpu_class_by_name(cpu_model);
+    if (oc == NULL) {
+        return NULL;
+    }
+    cpu = SUPERH_CPU(object_new(object_class_get_name(oc)));
+    env = &cpu->env;
+    env->cpu_model_str = cpu_model;
+
+    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
+
+    return cpu;
+}
+
+static void sh7750r_cpu_initfn(Object *obj)
+{
+    SuperHCPU *cpu = SUPERH_CPU(obj);
+    CPUSH4State *env = &cpu->env;
+
+    env->id = SH_CPU_SH7750R;
+    env->features = SH_FEATURE_BCR3_AND_BCR4;
+}
+
+static void sh7750r_class_init(ObjectClass *oc, void *data)
+{
+    SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+
+    scc->name = "SH7750R";
+    scc->pvr = 0x00050000;
+    scc->prr = 0x00000100;
+    scc->cvr = 0x00110000;
+}
+
+static const TypeInfo sh7750r_type_info = {
+    .name = TYPE_SH7750R_CPU,
+    .parent = TYPE_SUPERH_CPU,
+    .class_init = sh7750r_class_init,
+    .instance_init = sh7750r_cpu_initfn,
+};
+
+static void sh7751r_cpu_initfn(Object *obj)
+{
+    SuperHCPU *cpu = SUPERH_CPU(obj);
+    CPUSH4State *env = &cpu->env;
+
+    env->id = SH_CPU_SH7751R;
+    env->features = SH_FEATURE_BCR3_AND_BCR4;
+}
+
+static void sh7751r_class_init(ObjectClass *oc, void *data)
+{
+    SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+
+    scc->name = "SH7751R";
+    scc->pvr = 0x04050005;
+    scc->prr = 0x00000113;
+    scc->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */
+}
+
+static const TypeInfo sh7751r_type_info = {
+    .name = TYPE_SH7751R_CPU,
+    .parent = TYPE_SUPERH_CPU,
+    .class_init = sh7751r_class_init,
+    .instance_init = sh7751r_cpu_initfn,
+};
+
+static void sh7785_cpu_initfn(Object *obj)
+{
+    SuperHCPU *cpu = SUPERH_CPU(obj);
+    CPUSH4State *env = &cpu->env;
+
+    env->id = SH_CPU_SH7785;
+    env->features = SH_FEATURE_SH4A;
+}
+
+static void sh7785_class_init(ObjectClass *oc, void *data)
+{
+    SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+
+    scc->name = "SH7785";
+    scc->pvr = 0x10300700;
+    scc->prr = 0x00000200;
+    scc->cvr = 0x71440211;
+}
+
+static const TypeInfo sh7785_type_info = {
+    .name = TYPE_SH7785_CPU,
+    .parent = TYPE_SUPERH_CPU,
+    .class_init = sh7785_class_init,
+    .instance_init = sh7785_cpu_initfn,
+};
+
 static void superh_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     SuperHCPU *cpu = SUPERH_CPU(dev);
@@ -98,6 +272,8 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
     scc->parent_reset = cc->reset;
     cc->reset = superh_cpu_reset;
 
+    cc->class_by_name = superh_cpu_class_by_name;
+    cc->do_interrupt = superh_cpu_do_interrupt;
     dc->vmsd = &vmstate_sh_cpu;
 }
 
@@ -106,7 +282,7 @@ static const TypeInfo superh_cpu_type_info = {
     .parent = TYPE_CPU,
     .instance_size = sizeof(SuperHCPU),
     .instance_init = superh_cpu_initfn,
-    .abstract = false,
+    .abstract = true,
     .class_size = sizeof(SuperHCPUClass),
     .class_init = superh_cpu_class_init,
 };
@@ -114,6 +290,9 @@ static const TypeInfo superh_cpu_type_info = {
 static void superh_cpu_register_types(void)
 {
     type_register_static(&superh_cpu_type_info);
+    type_register_static(&sh7750r_type_info);
+    type_register_static(&sh7751r_type_info);
+    type_register_static(&sh7785_type_info);
 }
 
 type_init(superh_cpu_register_types)
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index 49dcd9e7f3..fd7da92548 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -179,9 +179,6 @@ typedef struct CPUSH4State {
     CPU_COMMON
 
     int id;			/* CPU model */
-    uint32_t pvr;		/* Processor Version Register */
-    uint32_t prr;		/* Processor Revision Register */
-    uint32_t cvr;		/* Cache Version Register */
 
     void *intc_handle;
     int in_sleep;		/* SR_BL ignored during sleep */
@@ -199,7 +196,6 @@ int cpu_sh4_signal_handler(int host_signum, void *pinfo,
 int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault
-void do_interrupt(CPUSH4State * env);
 
 void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 #if !defined(CONFIG_USER_ONLY)
@@ -372,9 +368,7 @@ static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc,
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUSH4State *env = &SUPERH_CPU(cpu)->env;
-
-    return env->interrupt_request & CPU_INTERRUPT_HARD;
+    return cpu->interrupt_request & CPU_INTERRUPT_HARD;
 }
 
 #include "exec/exec-all.h"
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index ddebc78964..0a9cb3ac98 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -31,9 +31,12 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUSH4State *env)
+void superh_cpu_do_interrupt(CPUState *cs)
 {
-  env->exception_index = -1;
+    SuperHCPU *cpu = SUPERH_CPU(cs);
+    CPUSH4State *env = &cpu->env;
+
+    env->exception_index = -1;
 }
 
 int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
@@ -78,9 +81,11 @@ int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
 #define MMU_DADDR_ERROR_READ     (-12)
 #define MMU_DADDR_ERROR_WRITE    (-13)
 
-void do_interrupt(CPUSH4State * env)
+void superh_cpu_do_interrupt(CPUState *cs)
 {
-    int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD;
+    SuperHCPU *cpu = SUPERH_CPU(cs);
+    CPUSH4State *env = &cpu->env;
+    int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD;
     int do_exp, irq_vector = env->exception_index;
 
     /* prioritize exceptions over interrupts */
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 09e3d23aff..e955e810b5 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -102,7 +102,9 @@ void helper_debug(CPUSH4State *env)
 
 void helper_sleep(CPUSH4State *env)
 {
-    env->halted = 1;
+    CPUState *cs = CPU(sh_env_get_cpu(env));
+
+    cs->halted = 1;
     env->in_sleep = 1;
     raise_exception(env, EXCP_HLT, 0);
 }
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 7f300e3444..14fdb8fc2d 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -175,90 +175,6 @@ void cpu_dump_state(CPUSH4State * env, FILE * f,
     }
 }
 
-typedef struct {
-    const char *name;
-    int id;
-    uint32_t pvr;
-    uint32_t prr;
-    uint32_t cvr;
-    uint32_t features;
-} sh4_def_t;
-
-static sh4_def_t sh4_defs[] = {
-    {
-	.name = "SH7750R",
-	.id = SH_CPU_SH7750R,
-	.pvr = 0x00050000,
-	.prr = 0x00000100,
-	.cvr = 0x00110000,
-	.features = SH_FEATURE_BCR3_AND_BCR4,
-    }, {
-	.name = "SH7751R",
-	.id = SH_CPU_SH7751R,
-	.pvr = 0x04050005,
-	.prr = 0x00000113,
-	.cvr = 0x00110000,	/* Neutered caches, should be 0x20480000 */
-	.features = SH_FEATURE_BCR3_AND_BCR4,
-    }, {
-	.name = "SH7785",
-	.id = SH_CPU_SH7785,
-	.pvr = 0x10300700,
-	.prr = 0x00000200,
-	.cvr = 0x71440211,
-	.features = SH_FEATURE_SH4A,
-     },
-};
-
-static const sh4_def_t *cpu_sh4_find_by_name(const char *name)
-{
-    int i;
-
-    if (strcasecmp(name, "any") == 0)
-	return &sh4_defs[0];
-
-    for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
-	if (strcasecmp(name, sh4_defs[i].name) == 0)
-	    return &sh4_defs[i];
-
-    return NULL;
-}
-
-void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
-	(*cpu_fprintf)(f, "%s\n", sh4_defs[i].name);
-}
-
-static void cpu_register(CPUSH4State *env, const sh4_def_t *def)
-{
-    env->pvr = def->pvr;
-    env->prr = def->prr;
-    env->cvr = def->cvr;
-    env->id = def->id;
-}
-
-SuperHCPU *cpu_sh4_init(const char *cpu_model)
-{
-    SuperHCPU *cpu;
-    CPUSH4State *env;
-    const sh4_def_t *def;
-
-    def = cpu_sh4_find_by_name(cpu_model);
-    if (!def)
-	return NULL;
-    cpu = SUPERH_CPU(object_new(TYPE_SUPERH_CPU));
-    env = &cpu->env;
-    env->features = def->features;
-    env->cpu_model_str = cpu_model;
-    cpu_register(env, def);
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return cpu;
-}
-
 static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
 {
     TranslationBlock *tb;
diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h
index efeeca0d97..d4fe89ebfd 100644
--- a/target-sparc/cpu-qom.h
+++ b/target-sparc/cpu-qom.h
@@ -75,4 +75,6 @@ static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env)
 
 #define ENV_OFFSET offsetof(SPARCCPU, env)
 
+void sparc_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 50def61848..ab1adfd7ea 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -891,6 +891,8 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
 
     scc->parent_reset = cc->reset;
     cc->reset = sparc_cpu_reset;
+
+    cc->do_interrupt = sparc_cpu_do_interrupt;
 }
 
 static const TypeInfo sparc_cpu_type_info = {
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index a2f2cc8989..6fa77789cd 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -553,7 +553,6 @@ int cpu_cwp_dec(CPUSPARCState *env1, int cwp);
 void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
 
 /* int_helper.c */
-void do_interrupt(CPUSPARCState *env);
 void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno);
 
 /* sun4m.c, sun4u.c */
@@ -762,9 +761,10 @@ static inline bool tb_am_enabled(int tb_flags)
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUSPARCState *env1 = &SPARC_CPU(cpu)->env;
+    SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
+    CPUSPARCState *env1 = &sparc_cpu->env;
 
-    return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+    return (cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
            cpu_interrupts_enabled(env1);
 }
 
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 58e7efe567..57c20af478 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -229,7 +229,9 @@ target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
 #ifndef TARGET_SPARC64
 void helper_power_down(CPUSPARCState *env)
 {
-    env->halted = 1;
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+
+    cs->halted = 1;
     env->exception_index = EXCP_HLT;
     env->pc = env->npc;
     env->npc = env->pc + 4;
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
index c35f522e0f..722146065a 100644
--- a/target-sparc/int32_helper.c
+++ b/target-sparc/int32_helper.c
@@ -58,8 +58,10 @@ static const char * const excp_names[0x80] = {
 };
 #endif
 
-void do_interrupt(CPUSPARCState *env)
+void sparc_cpu_do_interrupt(CPUState *cs)
 {
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
     int cwp, intno = env->exception_index;
 
     /* Compute PSR before exposing state.  */
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
index df37aa1d14..f411884c6e 100644
--- a/target-sparc/int64_helper.c
+++ b/target-sparc/int64_helper.c
@@ -59,8 +59,10 @@ static const char * const excp_names[0x80] = {
 };
 #endif
 
-void do_interrupt(CPUSPARCState *env)
+void sparc_cpu_do_interrupt(CPUState *cs)
 {
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
     int intno = env->exception_index;
     trap_state *tsptr;
 
diff --git a/target-unicore32/cpu-qom.h b/target-unicore32/cpu-qom.h
index c6590bdf01..ba4dee4b9f 100644
--- a/target-unicore32/cpu-qom.h
+++ b/target-unicore32/cpu-qom.h
@@ -60,4 +60,6 @@ static inline UniCore32CPU *uc32_env_get_cpu(CPUUniCore32State *env)
 
 #define ENV_OFFSET offsetof(UniCore32CPU, env)
 
+void uc32_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index b7024c85bb..66a1a74646 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -132,6 +132,7 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data)
     dc->realize = uc32_cpu_realizefn;
 
     cc->class_by_name = uc32_cpu_class_by_name;
+    cc->do_interrupt = uc32_cpu_do_interrupt;
     dc->vmsd = &vmstate_uc32_cpu;
 }
 
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index ae9a9d623d..5b2b9d1cc7 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -176,14 +176,11 @@ static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc
 }
 
 void uc32_translate_init(void);
-void do_interrupt(CPUUniCore32State *);
 void switch_mode(CPUUniCore32State *, int);
 
 static inline bool cpu_has_work(CPUState *cpu)
 {
-    CPUUniCore32State *env = &UNICORE32_CPU(cpu)->env;
-
-    return env->interrupt_request &
+    return cpu->interrupt_request &
         (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
 }
 
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 7eeb9bc633..61eb2c374a 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -242,8 +242,11 @@ void switch_mode(CPUUniCore32State *env, int mode)
     }
 }
 
-void do_interrupt(CPUUniCore32State *env)
+void uc32_cpu_do_interrupt(CPUState *cs)
 {
+    UniCore32CPU *cpu = UNICORE32_CPU(cs);
+    CPUUniCore32State *env = &cpu->env;
+
     cpu_abort(env, "NO interrupt in user mode\n");
 }
 
diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c
index fc27100f27..eadaeb11ab 100644
--- a/target-unicore32/softmmu.c
+++ b/target-unicore32/softmmu.c
@@ -72,8 +72,10 @@ void switch_mode(CPUUniCore32State *env, int mode)
 }
 
 /* Handle a CPU exception.  */
-void do_interrupt(CPUUniCore32State *env)
+void uc32_cpu_do_interrupt(CPUState *cs)
 {
+    UniCore32CPU *cpu = UNICORE32_CPU(cs);
+    CPUUniCore32State *env = &cpu->env;
     uint32_t addr;
     int new_mode;
 
@@ -112,7 +114,7 @@ void do_interrupt(CPUUniCore32State *env)
     /* The PC already points to the proper instruction.  */
     env->regs[30] = env->regs[31];
     env->regs[31] = addr;
-    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 
 static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address,
diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
index c78136bf72..af0ce2823c 100644
--- a/target-xtensa/cpu-qom.h
+++ b/target-xtensa/cpu-qom.h
@@ -80,4 +80,6 @@ static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env)
 
 #define ENV_OFFSET offsetof(XtensaCPU, env)
 
+void xtensa_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index 785e56d367..6e93dd8d24 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -101,6 +101,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
     xcc->parent_reset = cc->reset;
     cc->reset = xtensa_cpu_reset;
 
+    cc->do_interrupt = xtensa_cpu_do_interrupt;
     dc->vmsd = &vmstate_xtensa_cpu;
 }
 
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index dece224478..6c9fc35dcc 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -388,7 +388,6 @@ void xtensa_translate_init(void);
 void xtensa_breakpoint_handler(CPUXtensaState *env);
 int cpu_xtensa_exec(CPUXtensaState *s);
 void xtensa_register_core(XtensaConfigList *node);
-void do_interrupt(CPUXtensaState *s);
 void check_interrupts(CPUXtensaState *s);
 void xtensa_irq_init(CPUXtensaState *env);
 void *xtensa_get_extint(CPUXtensaState *env, unsigned extint);
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index a8a64932da..6f613c66a6 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -178,8 +178,11 @@ static void handle_interrupt(CPUXtensaState *env)
     }
 }
 
-void do_interrupt(CPUXtensaState *env)
+void xtensa_cpu_do_interrupt(CPUState *cs)
 {
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+    CPUXtensaState *env = &cpu->env;
+
     if (env->exception_index == EXC_IRQ) {
         qemu_log_mask(CPU_LOG_INT,
                 "%s(EXC_IRQ) level = %d, cintlevel = %d, "
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 3813a72626..1037101f2e 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -373,6 +373,8 @@ void HELPER(dump_state)(CPUXtensaState *env)
 
 void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
 {
+    CPUState *cpu;
+
     env->pc = pc;
     env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
         (intlevel << PS_INTLEVEL_SHIFT);
@@ -382,8 +384,9 @@ void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
         return;
     }
 
+    cpu = CPU(xtensa_env_get_cpu(env));
     env->halt_clock = qemu_get_clock_ns(vm_clock);
-    env->halted = 1;
+    cpu->halted = 1;
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
         xtensa_rearm_ccompare_timer(env);
     }
diff --git a/tpm/Makefile.objs b/tpm/Makefile.objs
new file mode 100644
index 0000000000..86768244e4
--- /dev/null
+++ b/tpm/Makefile.objs
@@ -0,0 +1,6 @@
+common-obj-y = tpm.o
+ifeq ($(CONFIG_TPM),y)
+common-obj-y += tpm_backend.o
+common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
+common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
+endif
diff --git a/tpm/tpm.c b/tpm/tpm.c
new file mode 100644
index 0000000000..ffd24956d7
--- /dev/null
+++ b/tpm/tpm.c
@@ -0,0 +1,357 @@
+/*
+ * TPM configuration
+ *
+ * Copyright (C) 2011-2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@us.ibm.com>
+ *
+ * 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 net.c
+ */
+#include "config-host.h"
+
+#include "monitor/monitor.h"
+#include "qapi/qmp/qerror.h"
+#include "tpm_int.h"
+#include "tpm/tpm.h"
+#include "qemu/config-file.h"
+#include "qmp-commands.h"
+
+static QLIST_HEAD(, TPMBackend) tpm_backends =
+    QLIST_HEAD_INITIALIZER(tpm_backends);
+
+
+#define TPM_MAX_MODELS      1
+#define TPM_MAX_DRIVERS     1
+
+static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
+    NULL,
+};
+
+static enum TpmModel tpm_models[TPM_MAX_MODELS] = {
+    -1,
+};
+
+int tpm_register_model(enum TpmModel model)
+{
+    int i;
+
+    for (i = 0; i < TPM_MAX_MODELS; i++) {
+        if (tpm_models[i] == -1) {
+            tpm_models[i] = model;
+            return 0;
+        }
+    }
+    error_report("Could not register TPM model");
+    return 1;
+}
+
+static bool tpm_model_is_registered(enum TpmModel model)
+{
+    int i;
+
+    for (i = 0; i < TPM_MAX_MODELS; i++) {
+        if (tpm_models[i] == model) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Write an error message in the given output buffer.
+ */
+void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
+{
+    if (out_len >= sizeof(struct tpm_resp_hdr)) {
+        struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
+
+        resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
+        resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
+        resp->errcode = cpu_to_be32(TPM_FAIL);
+    }
+}
+
+const TPMDriverOps *tpm_get_backend_driver(const char *type)
+{
+    int i;
+
+    for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) {
+        if (!strcmp(TpmType_lookup[be_drivers[i]->type], type)) {
+            return be_drivers[i];
+        }
+    }
+
+    return NULL;
+}
+
+#ifdef CONFIG_TPM
+
+int tpm_register_driver(const TPMDriverOps *tdo)
+{
+    int i;
+
+    for (i = 0; i < TPM_MAX_DRIVERS; i++) {
+        if (!be_drivers[i]) {
+            be_drivers[i] = tdo;
+            return 0;
+        }
+    }
+    error_report("Could not register TPM driver");
+    return 1;
+}
+
+/*
+ * Walk the list of available TPM backend drivers and display them on the
+ * screen.
+ */
+void tpm_display_backend_drivers(void)
+{
+    int i;
+
+    fprintf(stderr, "Supported TPM types (choose only one):\n");
+
+    for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) {
+        fprintf(stderr, "%12s   %s\n",
+                TpmType_lookup[be_drivers[i]->type], be_drivers[i]->desc());
+    }
+    fprintf(stderr, "\n");
+}
+
+/*
+ * Find the TPM with the given Id
+ */
+TPMBackend *qemu_find_tpm(const char *id)
+{
+    TPMBackend *drv;
+
+    if (id) {
+        QLIST_FOREACH(drv, &tpm_backends, list) {
+            if (!strcmp(drv->id, id)) {
+                return drv;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static int configure_tpm(QemuOpts *opts)
+{
+    const char *value;
+    const char *id;
+    const TPMDriverOps *be;
+    TPMBackend *drv;
+
+    if (!QLIST_EMPTY(&tpm_backends)) {
+        error_report("Only one TPM is allowed.\n");
+        return 1;
+    }
+
+    id = qemu_opts_id(opts);
+    if (id == NULL) {
+        qerror_report(QERR_MISSING_PARAMETER, "id");
+        return 1;
+    }
+
+    value = qemu_opt_get(opts, "type");
+    if (!value) {
+        qerror_report(QERR_MISSING_PARAMETER, "type");
+        tpm_display_backend_drivers();
+        return 1;
+    }
+
+    be = tpm_get_backend_driver(value);
+    if (be == NULL) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+                      "a TPM backend type");
+        tpm_display_backend_drivers();
+        return 1;
+    }
+
+    drv = be->create(opts, id);
+    if (!drv) {
+        return 1;
+    }
+
+    QLIST_INSERT_HEAD(&tpm_backends, drv, list);
+
+    return 0;
+}
+
+static int tpm_init_tpmdev(QemuOpts *opts, void *dummy)
+{
+    return configure_tpm(opts);
+}
+
+/*
+ * Walk the list of TPM backend drivers that are in use and call their
+ * destroy function to have them cleaned up.
+ */
+void tpm_cleanup(void)
+{
+    TPMBackend *drv, *next;
+
+    QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) {
+        QLIST_REMOVE(drv, list);
+        drv->ops->destroy(drv);
+    }
+}
+
+/*
+ * Initialize the TPM. Process the tpmdev command line options describing the
+ * TPM backend.
+ */
+int tpm_init(void)
+{
+    if (qemu_opts_foreach(qemu_find_opts("tpmdev"),
+                          tpm_init_tpmdev, NULL, 1) != 0) {
+        return -1;
+    }
+
+    atexit(tpm_cleanup);
+
+    return 0;
+}
+
+/*
+ * Parse the TPM configuration options.
+ * To display all available TPM backends the user may use '-tpmdev help'
+ */
+int tpm_config_parse(QemuOptsList *opts_list, const char *optarg)
+{
+    QemuOpts *opts;
+
+    if (!strcmp(optarg, "help")) {
+        tpm_display_backend_drivers();
+        return -1;
+    }
+    opts = qemu_opts_parse(opts_list, optarg, 1);
+    if (!opts) {
+        return -1;
+    }
+    return 0;
+}
+
+#endif /* CONFIG_TPM */
+
+static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type)
+{
+    int i;
+
+    for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) {
+        if (be_drivers[i]->type == type) {
+            return be_drivers[i];
+        }
+    }
+    return NULL;
+}
+
+static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
+{
+    TPMInfo *res = g_new0(TPMInfo, 1);
+    TPMPassthroughOptions *tpo;
+
+    res->id = g_strdup(drv->id);
+    res->model = drv->fe_model;
+    res->type = drv->ops->type;
+    res->tpm_options = g_new0(TpmTypeOptions, 1);
+
+    switch (res->type) {
+    case TPM_TYPE_PASSTHROUGH:
+        res->tpm_options->kind = TPM_TYPE_OPTIONS_KIND_TPM_PASSTHROUGH_OPTIONS;
+        tpo = g_new0(TPMPassthroughOptions, 1);
+        res->tpm_options->tpm_passthrough_options = tpo;
+        if (drv->path) {
+            tpo->path = g_strdup(drv->path);
+            tpo->has_path = true;
+        }
+        if (drv->cancel_path) {
+            tpo->cancel_path = g_strdup(drv->cancel_path);
+            tpo->has_cancel_path = true;
+        }
+        break;
+    case TPM_TYPE_MAX:
+        break;
+    }
+
+    return res;
+}
+
+/*
+ * Walk the list of active TPM backends and collect information about them
+ * following the schema description in qapi-schema.json.
+ */
+TPMInfoList *qmp_query_tpm(Error **errp)
+{
+    TPMBackend *drv;
+    TPMInfoList *info, *head = NULL, *cur_item = NULL;
+
+    QLIST_FOREACH(drv, &tpm_backends, list) {
+        if (!tpm_model_is_registered(drv->fe_model)) {
+            continue;
+        }
+        info = g_new0(TPMInfoList, 1);
+        info->value = qmp_query_tpm_inst(drv);
+
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
+        }
+    }
+
+    return head;
+}
+
+TpmTypeList *qmp_query_tpm_types(Error **errp)
+{
+    unsigned int i = 0;
+    TpmTypeList *head = NULL, *prev = NULL, *cur_item;
+
+    for (i = 0; i < TPM_TYPE_MAX; i++) {
+        if (!tpm_driver_find_by_type(i)) {
+            continue;
+        }
+        cur_item = g_new0(TpmTypeList, 1);
+        cur_item->value = i;
+
+        if (prev) {
+            prev->next = cur_item;
+        }
+        if (!head) {
+            head = cur_item;
+        }
+        prev = cur_item;
+    }
+
+    return head;
+}
+
+TpmModelList *qmp_query_tpm_models(Error **errp)
+{
+    unsigned int i = 0;
+    TpmModelList *head = NULL, *prev = NULL, *cur_item;
+
+    for (i = 0; i < TPM_MODEL_MAX; i++) {
+        if (!tpm_model_is_registered(i)) {
+            continue;
+        }
+        cur_item = g_new0(TpmModelList, 1);
+        cur_item->value = i;
+
+        if (prev) {
+            prev->next = cur_item;
+        }
+        if (!head) {
+            head = cur_item;
+        }
+        prev = cur_item;
+    }
+
+    return head;
+}
diff --git a/tpm/tpm_backend.c b/tpm/tpm_backend.c
new file mode 100644
index 0000000000..4144ef7d76
--- /dev/null
+++ b/tpm/tpm_backend.c
@@ -0,0 +1,58 @@
+/*
+ *  common TPM backend driver functions
+ *
+ *  Copyright (c) 2012-2013 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ * 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 "tpm/tpm.h"
+#include "qemu/thread.h"
+#include "tpm_backend.h"
+
+void tpm_backend_thread_deliver_request(TPMBackendThread *tbt)
+{
+   g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD, NULL);
+}
+
+void tpm_backend_thread_create(TPMBackendThread *tbt,
+                               GFunc func, gpointer user_data)
+{
+    if (!tbt->pool) {
+        tbt->pool = g_thread_pool_new(func, user_data, 1, TRUE, NULL);
+        g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_INIT, NULL);
+    }
+}
+
+void tpm_backend_thread_end(TPMBackendThread *tbt)
+{
+    if (tbt->pool) {
+        g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_END, NULL);
+        g_thread_pool_free(tbt->pool, FALSE, TRUE);
+        tbt->pool = NULL;
+    }
+}
+
+void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
+                                  GFunc func, gpointer user_data)
+{
+    if (!tbt->pool) {
+        tpm_backend_thread_create(tbt, func, user_data);
+    } else {
+        g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_TPM_RESET,
+                           NULL);
+    }
+}
diff --git a/tpm/tpm_backend.h b/tpm/tpm_backend.h
new file mode 100644
index 0000000000..05d94d0f5b
--- /dev/null
+++ b/tpm/tpm_backend.h
@@ -0,0 +1,45 @@
+/*
+ *  common TPM backend driver functions
+ *
+ *  Copyright (c) 2012-2013 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ * 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/>
+ */
+
+#ifndef TPM_TPM_BACKEND_H
+#define TPM_TPM_BACKEND_H
+
+#include <glib.h>
+
+typedef struct TPMBackendThread {
+    GThreadPool *pool;
+} TPMBackendThread;
+
+void tpm_backend_thread_deliver_request(TPMBackendThread *tbt);
+void tpm_backend_thread_create(TPMBackendThread *tbt,
+                               GFunc func, gpointer user_data);
+void tpm_backend_thread_end(TPMBackendThread *tbt);
+void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
+                                  GFunc func, gpointer user_data);
+
+typedef enum TPMBackendCmd {
+    TPM_BACKEND_CMD_INIT = 1,
+    TPM_BACKEND_CMD_PROCESS_CMD,
+    TPM_BACKEND_CMD_END,
+    TPM_BACKEND_CMD_TPM_RESET,
+} TPMBackendCmd;
+
+#endif /* TPM_TPM_BACKEND_H */
diff --git a/tpm/tpm_int.h b/tpm/tpm_int.h
new file mode 100644
index 0000000000..f7056436cc
--- /dev/null
+++ b/tpm/tpm_int.h
@@ -0,0 +1,116 @@
+/*
+ * TPM configuration
+ *
+ * Copyright (C) 2011-2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@us.ibm.com>
+ *
+ * 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 TPM_TPM_INT_H
+#define TPM_TPM_INT_H
+
+#include "exec/memory.h"
+#include "tpm/tpm_tis.h"
+
+struct TPMDriverOps;
+typedef struct TPMDriverOps TPMDriverOps;
+
+typedef struct TPMPassthruState TPMPassthruState;
+
+typedef struct TPMBackend {
+    char *id;
+    enum TpmModel fe_model;
+    char *path;
+    char *cancel_path;
+    const TPMDriverOps *ops;
+
+    union {
+        TPMPassthruState *tpm_pt;
+    } s;
+
+    QLIST_ENTRY(TPMBackend) list;
+} TPMBackend;
+
+/* overall state of the TPM interface */
+typedef struct TPMState {
+    ISADevice busdev;
+    MemoryRegion mmio;
+
+    union {
+        TPMTISEmuState tis;
+    } s;
+
+    uint8_t     locty_number;
+    TPMLocality *locty_data;
+
+    char *backend;
+    TPMBackend *be_driver;
+} TPMState;
+
+#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
+
+typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty);
+
+struct TPMDriverOps {
+    enum TpmType type;
+    /* get a descriptive text of the backend to display to the user */
+    const char *(*desc)(void);
+
+    TPMBackend *(*create)(QemuOpts *opts, const char *id);
+    void (*destroy)(TPMBackend *t);
+
+    /* initialize the backend */
+    int (*init)(TPMBackend *t, TPMState *s, TPMRecvDataCB *datacb);
+    /* start up the TPM on the backend */
+    int (*startup_tpm)(TPMBackend *t);
+    /* returns true if nothing will ever answer TPM requests */
+    bool (*had_startup_error)(TPMBackend *t);
+
+    size_t (*realloc_buffer)(TPMSizedBuffer *sb);
+
+    void (*deliver_request)(TPMBackend *t);
+
+    void (*reset)(TPMBackend *t);
+
+    void (*cancel_cmd)(TPMBackend *t);
+
+    bool (*get_tpm_established_flag)(TPMBackend *t);
+};
+
+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_FAIL                  9
+
+#define TPM_ORD_GetTicks          0xf1
+
+TPMBackend *qemu_find_tpm(const char *id);
+int tpm_register_model(enum TpmModel model);
+int tpm_register_driver(const TPMDriverOps *tdo);
+void tpm_display_backend_drivers(void);
+const TPMDriverOps *tpm_get_backend_driver(const char *type);
+void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len);
+
+extern const TPMDriverOps tpm_passthrough_driver;
+
+#endif /* TPM_TPM_INT_H */
diff --git a/tpm/tpm_passthrough.c b/tpm/tpm_passthrough.c
new file mode 100644
index 0000000000..24aff4d69c
--- /dev/null
+++ b/tpm/tpm_passthrough.c
@@ -0,0 +1,530 @@
+/*
+ *  passthrough TPM driver
+ *
+ *  Copyright (c) 2010 - 2013 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ *  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 <dirent.h>
+
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qemu/sockets.h"
+#include "tpm_int.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "tpm_tis.h"
+#include "tpm_backend.h"
+
+/* #define DEBUG_TPM */
+
+#ifdef DEBUG_TPM
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+/* data structures */
+
+typedef struct TPMPassthruThreadParams {
+    TPMState *tpm_state;
+
+    TPMRecvDataCB *recv_data_callback;
+    TPMBackend *tb;
+} TPMPassthruThreadParams;
+
+struct TPMPassthruState {
+    TPMBackendThread tbt;
+
+    TPMPassthruThreadParams tpm_thread_params;
+
+    char *tpm_dev;
+    int tpm_fd;
+    bool tpm_executing;
+    bool tpm_op_canceled;
+    int cancel_fd;
+    bool had_startup_error;
+};
+
+#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
+
+/* functions */
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
+
+static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
+{
+    return send_all(fd, buf, len);
+}
+
+static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
+{
+    return recv_all(fd, buf, len, true);
+}
+
+static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf)
+{
+    struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf;
+
+    return be32_to_cpu(resp->len);
+}
+
+static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
+                                        const uint8_t *in, uint32_t in_len,
+                                        uint8_t *out, uint32_t out_len)
+{
+    int ret;
+
+    tpm_pt->tpm_op_canceled = false;
+    tpm_pt->tpm_executing = true;
+
+    ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
+    if (ret != in_len) {
+        if (!tpm_pt->tpm_op_canceled ||
+            (tpm_pt->tpm_op_canceled && errno != ECANCELED)) {
+            error_report("tpm_passthrough: error while transmitting data "
+                         "to TPM: %s (%i)\n",
+                         strerror(errno), errno);
+        }
+        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 ||
+            (tpm_pt->tpm_op_canceled && errno != ECANCELED)) {
+            error_report("tpm_passthrough: error while reading data from "
+                         "TPM: %s (%i)\n",
+                         strerror(errno), errno);
+        }
+    } else if (ret < sizeof(struct tpm_resp_hdr) ||
+               tpm_passthrough_get_size_from_buffer(out) != ret) {
+        ret = -1;
+        error_report("tpm_passthrough: received invalid response "
+                     "packet from TPM\n");
+    }
+
+err_exit:
+    if (ret < 0) {
+        tpm_write_fatal_error_response(out, out_len);
+    }
+
+    tpm_pt->tpm_executing = false;
+
+    return ret;
+}
+
+static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
+                                         const TPMLocality *locty_data)
+{
+    return tpm_passthrough_unix_tx_bufs(tpm_pt,
+                                        locty_data->w_buffer.buffer,
+                                        locty_data->w_offset,
+                                        locty_data->r_buffer.buffer,
+                                        locty_data->r_buffer.size);
+}
+
+static void tpm_passthrough_worker_thread(gpointer data,
+                                          gpointer user_data)
+{
+    TPMPassthruThreadParams *thr_parms = user_data;
+    TPMPassthruState *tpm_pt = thr_parms->tb->s.tpm_pt;
+    TPMBackendCmd cmd = (TPMBackendCmd)data;
+
+    DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
+
+    switch (cmd) {
+    case TPM_BACKEND_CMD_PROCESS_CMD:
+        tpm_passthrough_unix_transfer(tpm_pt,
+                                      thr_parms->tpm_state->locty_data);
+
+        thr_parms->recv_data_callback(thr_parms->tpm_state,
+                                      thr_parms->tpm_state->locty_number);
+        break;
+    case TPM_BACKEND_CMD_INIT:
+    case TPM_BACKEND_CMD_END:
+    case TPM_BACKEND_CMD_TPM_RESET:
+        /* nothing to do */
+        break;
+    }
+}
+
+/*
+ * Start the TPM (thread). If it had been started before, then terminate
+ * and start it again.
+ */
+static int tpm_passthrough_startup_tpm(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+
+    /* terminate a running TPM */
+    tpm_backend_thread_end(&tpm_pt->tbt);
+
+    tpm_backend_thread_create(&tpm_pt->tbt,
+                              tpm_passthrough_worker_thread,
+                              &tb->s.tpm_pt->tpm_thread_params);
+
+    return 0;
+}
+
+static void tpm_passthrough_reset(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+
+    DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n");
+
+    tpm_passthrough_cancel_cmd(tb);
+
+    tpm_backend_thread_end(&tpm_pt->tbt);
+
+    tpm_pt->had_startup_error = false;
+}
+
+static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
+                                TPMRecvDataCB *recv_data_cb)
+{
+    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+
+    tpm_pt->tpm_thread_params.tpm_state = s;
+    tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
+    tpm_pt->tpm_thread_params.tb = tb;
+
+    return 0;
+}
+
+static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
+{
+    return false;
+}
+
+static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+
+    return tpm_pt->had_startup_error;
+}
+
+static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
+{
+    size_t wanted_size = 4096; /* Linux tpm.c buffer size */
+
+    if (sb->size != wanted_size) {
+        sb->buffer = g_realloc(sb->buffer, wanted_size);
+        sb->size = wanted_size;
+    }
+    return sb->size;
+}
+
+static void tpm_passthrough_deliver_request(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+
+    tpm_backend_thread_deliver_request(&tpm_pt->tbt);
+}
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+    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) {
+            n = write(tpm_pt->cancel_fd, "-", 1);
+            if (n != 1) {
+                error_report("Canceling TPM command failed: %s\n",
+                             strerror(errno));
+            } else {
+                tpm_pt->tpm_op_canceled = true;
+            }
+        } else {
+            error_report("Cannot cancel TPM command due to missing "
+                         "TPM sysfs cancel entry");
+        }
+    }
+}
+
+static const char *tpm_passthrough_create_desc(void)
+{
+    return "Passthrough TPM backend driver";
+}
+
+/*
+ * A basic test of a TPM device. We expect a well formatted response header
+ * (error response is fine) within one second.
+ */
+static int tpm_passthrough_test_tpmdev(int fd)
+{
+    struct tpm_req_hdr req = {
+        .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
+        .len = cpu_to_be32(sizeof(req)),
+        .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
+    };
+    struct tpm_resp_hdr *resp;
+    fd_set readfds;
+    int n;
+    struct timeval tv = {
+        .tv_sec = 1,
+        .tv_usec = 0,
+    };
+    unsigned char buf[1024];
+
+    n = write(fd, &req, sizeof(req));
+    if (n < 0) {
+        return errno;
+    }
+    if (n != sizeof(req)) {
+        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, &buf, sizeof(buf));
+    if (n < sizeof(struct tpm_resp_hdr)) {
+        return EFAULT;
+    }
+
+    resp = (struct tpm_resp_hdr *)buf;
+    /* check the header */
+    if (be16_to_cpu(resp->tag) != TPM_TAG_RSP_COMMAND ||
+        be32_to_cpu(resp->len) != n) {
+        return EBADMSG;
+    }
+
+    return 0;
+}
+
+/*
+ * Check whether the given base path, e.g.,  /sys/class/misc/tpm0/device,
+ * is the sysfs directory of a TPM. A TPM sysfs directory should be uniquely
+ * recognizable by the file entries 'pcrs' and 'cancel'.
+ * Upon success 'true' is returned and the basebath buffer has '/cancel'
+ * appended.
+ */
+static bool tpm_passthrough_check_sysfs_cancel(char *basepath, size_t bufsz)
+{
+    char path[PATH_MAX];
+    struct stat statbuf;
+
+    snprintf(path, sizeof(path), "%s/pcrs", basepath);
+    if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) {
+        return false;
+    }
+
+    snprintf(path, sizeof(path), "%s/cancel", basepath);
+    if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) {
+        return false;
+    }
+
+    strncpy(basepath, path, bufsz);
+
+    return true;
+}
+
+/*
+ * 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.
+ */
+static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
+{
+    int fd = -1;
+    unsigned int idx;
+    DIR *pnp_dir;
+    char path[PATH_MAX];
+    struct dirent entry, *result;
+    int len;
+
+    if (tb->cancel_path) {
+        fd = qemu_open(tb->cancel_path, O_WRONLY);
+        if (fd < 0) {
+            error_report("Could not open TPM cancel path : %s",
+                         strerror(errno));
+        }
+        return fd;
+    }
+
+    snprintf(path, sizeof(path), "/sys/class/misc");
+    pnp_dir = opendir(path);
+    if (pnp_dir != NULL) {
+        while (readdir_r(pnp_dir, &entry, &result) == 0 &&
+               result != NULL) {
+            /*
+             * only allow /sys/class/misc/tpm%u type of paths
+             */
+            if (sscanf(entry.d_name, "tpm%u%n", &idx, &len) < 1 ||
+                len <= strlen("tpm") ||
+                len != strlen(entry.d_name)) {
+                continue;
+            }
+
+            snprintf(path, sizeof(path), "/sys/class/misc/%s/device",
+                     entry.d_name);
+            if (!tpm_passthrough_check_sysfs_cancel(path, sizeof(path))) {
+                continue;
+            }
+
+            fd = qemu_open(path, O_WRONLY);
+            break;
+        }
+        closedir(pnp_dir);
+    }
+
+    if (fd >= 0) {
+        tb->cancel_path = g_strdup(path);
+    }
+
+    return fd;
+}
+
+static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
+{
+    const char *value;
+
+    value = qemu_opt_get(opts, "cancel-path");
+    if (value) {
+        tb->cancel_path = g_strdup(value);
+    }
+
+    value = qemu_opt_get(opts, "path");
+    if (!value) {
+        value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
+    }
+
+    tb->s.tpm_pt->tpm_dev = g_strdup(value);
+
+    tb->path = g_strdup(tb->s.tpm_pt->tpm_dev);
+
+    tb->s.tpm_pt->tpm_fd = qemu_open(tb->s.tpm_pt->tpm_dev, O_RDWR);
+    if (tb->s.tpm_pt->tpm_fd < 0) {
+        error_report("Cannot access TPM device using '%s': %s\n",
+                     tb->s.tpm_pt->tpm_dev, strerror(errno));
+        goto err_free_parameters;
+    }
+
+    if (tpm_passthrough_test_tpmdev(tb->s.tpm_pt->tpm_fd)) {
+        error_report("'%s' is not a TPM device.\n",
+                     tb->s.tpm_pt->tpm_dev);
+        goto err_close_tpmdev;
+    }
+
+    return 0;
+
+ err_close_tpmdev:
+    qemu_close(tb->s.tpm_pt->tpm_fd);
+    tb->s.tpm_pt->tpm_fd = -1;
+
+ err_free_parameters:
+    g_free(tb->path);
+    tb->path = NULL;
+
+    g_free(tb->s.tpm_pt->tpm_dev);
+    tb->s.tpm_pt->tpm_dev = NULL;
+
+    return 1;
+}
+
+static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
+{
+    TPMBackend *tb;
+
+    tb = g_new0(TPMBackend, 1);
+    tb->s.tpm_pt = g_new0(TPMPassthruState, 1);
+    tb->id = g_strdup(id);
+    /* let frontend set the fe_model to proper value */
+    tb->fe_model = -1;
+
+    tb->ops = &tpm_passthrough_driver;
+
+    if (tpm_passthrough_handle_device_opts(opts, tb)) {
+        goto err_exit;
+    }
+
+    tb->s.tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb);
+    if (tb->s.tpm_pt->cancel_fd < 0) {
+        goto err_exit;
+    }
+
+    return tb;
+
+err_exit:
+    g_free(tb->id);
+    g_free(tb->s.tpm_pt);
+    g_free(tb);
+
+    return NULL;
+}
+
+static void tpm_passthrough_destroy(TPMBackend *tb)
+{
+    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+
+    tpm_passthrough_cancel_cmd(tb);
+
+    tpm_backend_thread_end(&tpm_pt->tbt);
+
+    qemu_close(tpm_pt->tpm_fd);
+    qemu_close(tb->s.tpm_pt->cancel_fd);
+
+    g_free(tb->id);
+    g_free(tb->path);
+    g_free(tb->cancel_path);
+    g_free(tb->s.tpm_pt->tpm_dev);
+    g_free(tb->s.tpm_pt);
+    g_free(tb);
+}
+
+const TPMDriverOps tpm_passthrough_driver = {
+    .type                     = TPM_TYPE_PASSTHROUGH,
+    .desc                     = tpm_passthrough_create_desc,
+    .create                   = tpm_passthrough_create,
+    .destroy                  = tpm_passthrough_destroy,
+    .init                     = tpm_passthrough_init,
+    .startup_tpm              = tpm_passthrough_startup_tpm,
+    .realloc_buffer           = tpm_passthrough_realloc_buffer,
+    .reset                    = tpm_passthrough_reset,
+    .had_startup_error        = tpm_passthrough_get_startup_error,
+    .deliver_request          = tpm_passthrough_deliver_request,
+    .cancel_cmd               = tpm_passthrough_cancel_cmd,
+    .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
+};
+
+static void tpm_passthrough_register(void)
+{
+    tpm_register_driver(&tpm_passthrough_driver);
+}
+
+type_init(tpm_passthrough_register)
diff --git a/tpm/tpm_tis.c b/tpm/tpm_tis.c
new file mode 100644
index 0000000000..e93825eec1
--- /dev/null
+++ b/tpm/tpm_tis.c
@@ -0,0 +1,929 @@
+/*
+ * tpm_tis.c - QEMU's TPM TIS interface emulator
+ *
+ * Copyright (C) 2006,2010-2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger <stefanb@us.ibm.com>
+ *  David Safford <safford@us.ibm.com>
+ *
+ * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Implementation of the TIS interface according to specs found at
+ * http://www.trustedcomputinggroup.org. This implementation currently
+ * supports version 1.21, revision 1.0.
+ * In the developers menu choose the PC Client section then find the TIS
+ * specification.
+ */
+
+#include "tpm_int.h"
+#include "block/block.h"
+#include "exec/address-spaces.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/pci/pci_ids.h"
+#include "tpm/tpm_tis.h"
+#include "qemu-common.h"
+
+/*#define DEBUG_TIS */
+
+#ifdef DEBUG_TIS
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+/* whether the STS interrupt is supported */
+#define RAISE_STS_IRQ
+
+/* tis registers */
+#define TPM_TIS_REG_ACCESS                0x00
+#define TPM_TIS_REG_INT_ENABLE            0x08
+#define TPM_TIS_REG_INT_VECTOR            0x0c
+#define TPM_TIS_REG_INT_STATUS            0x10
+#define TPM_TIS_REG_INTF_CAPABILITY       0x14
+#define TPM_TIS_REG_STS                   0x18
+#define TPM_TIS_REG_DATA_FIFO             0x24
+#define TPM_TIS_REG_DID_VID               0xf00
+#define TPM_TIS_REG_RID                   0xf04
+
+/* vendor-specific registers */
+#define TPM_TIS_REG_DEBUG                 0xf90
+
+#define TPM_TIS_STS_VALID                 (1 << 7)
+#define TPM_TIS_STS_COMMAND_READY         (1 << 6)
+#define TPM_TIS_STS_TPM_GO                (1 << 5)
+#define TPM_TIS_STS_DATA_AVAILABLE        (1 << 4)
+#define TPM_TIS_STS_EXPECT                (1 << 3)
+#define TPM_TIS_STS_RESPONSE_RETRY        (1 << 1)
+
+#define TPM_TIS_BURST_COUNT_SHIFT         8
+#define TPM_TIS_BURST_COUNT(X) \
+    ((X) << TPM_TIS_BURST_COUNT_SHIFT)
+
+#define TPM_TIS_ACCESS_TPM_REG_VALID_STS  (1 << 7)
+#define TPM_TIS_ACCESS_ACTIVE_LOCALITY    (1 << 5)
+#define TPM_TIS_ACCESS_BEEN_SEIZED        (1 << 4)
+#define TPM_TIS_ACCESS_SEIZE              (1 << 3)
+#define TPM_TIS_ACCESS_PENDING_REQUEST    (1 << 2)
+#define TPM_TIS_ACCESS_REQUEST_USE        (1 << 1)
+#define TPM_TIS_ACCESS_TPM_ESTABLISHMENT  (1 << 0)
+
+#define TPM_TIS_INT_ENABLED               (1 << 31)
+#define TPM_TIS_INT_DATA_AVAILABLE        (1 << 0)
+#define TPM_TIS_INT_STS_VALID             (1 << 1)
+#define TPM_TIS_INT_LOCALITY_CHANGED      (1 << 2)
+#define TPM_TIS_INT_COMMAND_READY         (1 << 7)
+
+#define TPM_TIS_INT_POLARITY_MASK         (3 << 3)
+#define TPM_TIS_INT_POLARITY_LOW_LEVEL    (1 << 3)
+
+#ifndef RAISE_STS_IRQ
+
+#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
+                                      TPM_TIS_INT_DATA_AVAILABLE   | \
+                                      TPM_TIS_INT_COMMAND_READY)
+
+#else
+
+#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
+                                      TPM_TIS_INT_DATA_AVAILABLE   | \
+                                      TPM_TIS_INT_STS_VALID | \
+                                      TPM_TIS_INT_COMMAND_READY)
+
+#endif
+
+#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL  (1 << 4) /* support is mandatory */
+#define TPM_TIS_CAPABILITIES_SUPPORTED   (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
+                                          TPM_TIS_INTERRUPTS_SUPPORTED)
+
+#define TPM_TIS_TPM_DID       0x0001
+#define TPM_TIS_TPM_VID       PCI_VENDOR_ID_IBM
+#define TPM_TIS_TPM_RID       0x0001
+
+#define TPM_TIS_NO_DATA_BYTE  0xff
+
+/* local prototypes */
+
+static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
+                                  unsigned size);
+
+/* utility functions */
+
+static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
+{
+    return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
+}
+
+static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
+{
+    return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
+}
+
+static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
+{
+#ifdef DEBUG_TIS
+    uint32_t len, i;
+
+    len = tpm_tis_get_size_from_buffer(sb);
+    DPRINTF("tpm_tis: %s length = %d\n", string, len);
+    for (i = 0; i < len; i++) {
+        if (i && !(i % 16)) {
+            DPRINTF("\n");
+        }
+        DPRINTF("%.2X ", sb->buffer[i]);
+    }
+    DPRINTF("\n");
+#endif
+}
+
+/*
+ * Send a request to the TPM.
+ */
+static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+
+    tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
+
+    s->locty_number = locty;
+    s->locty_data = &tis->loc[locty];
+
+    /*
+     * w_offset serves as length indicator for length of data;
+     * it's reset when the response comes back
+     */
+    tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
+
+    s->be_driver->ops->deliver_request(s->be_driver);
+}
+
+/* raise an interrupt if allowed */
+static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+
+    if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
+        return;
+    }
+
+    if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
+        (tis->loc[locty].inte & irqmask)) {
+        DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
+        qemu_irq_raise(s->s.tis.irq);
+        tis->loc[locty].ints |= irqmask;
+    }
+}
+
+static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
+{
+    uint8_t l;
+
+    for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
+        if (l == locty) {
+            continue;
+        }
+        if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+    bool change = (s->s.tis.active_locty != new_active_locty);
+    bool is_seize;
+    uint8_t mask;
+
+    if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
+        is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
+                   tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
+
+        if (is_seize) {
+            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+        } else {
+            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
+                     TPM_TIS_ACCESS_REQUEST_USE);
+        }
+        /* reset flags on the old active locality */
+        tis->loc[s->s.tis.active_locty].access &= mask;
+
+        if (is_seize) {
+            tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
+        }
+    }
+
+    tis->active_locty = new_active_locty;
+
+    DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
+
+    if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
+        /* set flags on the new active locality */
+        tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
+        tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
+                                               TPM_TIS_ACCESS_SEIZE);
+    }
+
+    if (change) {
+        tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
+    }
+}
+
+/* abort -- this function switches the locality */
+static void tpm_tis_abort(TPMState *s, uint8_t locty)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+
+    tis->loc[locty].r_offset = 0;
+    tis->loc[locty].w_offset = 0;
+
+    DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
+
+    /*
+     * Need to react differently depending on who's aborting now and
+     * which locality will become active afterwards.
+     */
+    if (tis->aborting_locty == tis->next_locty) {
+        tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
+        tis->loc[tis->aborting_locty].sts = TPM_TIS_STS_COMMAND_READY;
+        tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
+    }
+
+    /* locality after abort is another one than the current one */
+    tpm_tis_new_active_locality(s, tis->next_locty);
+
+    tis->next_locty = TPM_TIS_NO_LOCALITY;
+    /* nobody's aborting a command anymore */
+    tis->aborting_locty = TPM_TIS_NO_LOCALITY;
+}
+
+/* prepare aborting current command */
+static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+    uint8_t busy_locty;
+
+    tis->aborting_locty = locty;
+    tis->next_locty = newlocty;  /* locality after successful abort */
+
+    /*
+     * only abort a command using an interrupt if currently executing
+     * a command AND if there's a valid connection to the vTPM.
+     */
+    for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
+        if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
+            /*
+             * request the backend to cancel. Some backends may not
+             * support it
+             */
+            s->be_driver->ops->cancel_cmd(s->be_driver);
+            return;
+        }
+    }
+
+    tpm_tis_abort(s, locty);
+}
+
+static void tpm_tis_receive_bh(void *opaque)
+{
+    TPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+    uint8_t locty = s->locty_number;
+
+    tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE;
+    tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
+    tis->loc[locty].r_offset = 0;
+    tis->loc[locty].w_offset = 0;
+
+    if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
+        tpm_tis_abort(s, locty);
+    }
+
+#ifndef RAISE_STS_IRQ
+    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
+#else
+    tpm_tis_raise_irq(s, locty,
+                      TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
+#endif
+}
+
+/*
+ * Callback from the TPM to indicate that the response was received.
+ */
+static void tpm_tis_receive_cb(TPMState *s, uint8_t locty)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+
+    assert(s->locty_number == locty);
+
+    qemu_bh_schedule(tis->bh);
+}
+
+/*
+ * Read a byte of response data
+ */
+static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
+{
+    TPMTISEmuState *tis = &s->s.tis;
+    uint32_t ret = TPM_TIS_NO_DATA_BYTE;
+    uint16_t len;
+
+    if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
+        len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
+
+        ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
+        if (tis->loc[locty].r_offset >= len) {
+            /* got last byte */
+            tis->loc[locty].sts = TPM_TIS_STS_VALID;
+#ifdef RAISE_STS_IRQ
+            tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
+#endif
+        }
+        DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x   [%d]\n",
+                ret, tis->loc[locty].r_offset-1);
+    }
+
+    return ret;
+}
+
+#ifdef DEBUG_TIS
+static void tpm_tis_dump_state(void *opaque, hwaddr addr)
+{
+    static const unsigned regs[] = {
+        TPM_TIS_REG_ACCESS,
+        TPM_TIS_REG_INT_ENABLE,
+        TPM_TIS_REG_INT_VECTOR,
+        TPM_TIS_REG_INT_STATUS,
+        TPM_TIS_REG_INTF_CAPABILITY,
+        TPM_TIS_REG_STS,
+        TPM_TIS_REG_DID_VID,
+        TPM_TIS_REG_RID,
+        0xfff};
+    int idx;
+    uint8_t locty = tpm_tis_locality_from_addr(addr);
+    hwaddr base = addr & ~0xfff;
+    TPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+
+    DPRINTF("tpm_tis: active locality      : %d\n"
+            "tpm_tis: state of locality %d : %d\n"
+            "tpm_tis: register dump:\n",
+            tis->active_locty,
+            locty, tis->loc[locty].state);
+
+    for (idx = 0; regs[idx] != 0xfff; idx++) {
+        DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
+                (uint32_t)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
+    }
+
+    DPRINTF("tpm_tis: read offset   : %d\n"
+            "tpm_tis: result buffer : ",
+            tis->loc[locty].r_offset);
+    for (idx = 0;
+         idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
+         idx++) {
+        DPRINTF("%c%02x%s",
+                tis->loc[locty].r_offset == idx ? '>' : ' ',
+                tis->loc[locty].r_buffer.buffer[idx],
+                ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
+    }
+    DPRINTF("\n"
+            "tpm_tis: write offset  : %d\n"
+            "tpm_tis: request buffer: ",
+            tis->loc[locty].w_offset);
+    for (idx = 0;
+         idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
+         idx++) {
+        DPRINTF("%c%02x%s",
+                tis->loc[locty].w_offset == idx ? '>' : ' ',
+                tis->loc[locty].w_buffer.buffer[idx],
+                ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
+    }
+    DPRINTF("\n");
+}
+#endif
+
+/*
+ * Read a register of the TIS interface
+ * See specs pages 33-63 for description of the registers
+ */
+static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    TPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+    uint16_t offset = addr & 0xffc;
+    uint8_t shift = (addr & 0x3) * 8;
+    uint32_t val = 0xffffffff;
+    uint8_t locty = tpm_tis_locality_from_addr(addr);
+    uint32_t avail;
+
+    if (s->be_driver->ops->had_startup_error(s->be_driver)) {
+        return val;
+    }
+
+    switch (offset) {
+    case TPM_TIS_REG_ACCESS:
+        /* never show the SEIZE flag even though we use it internally */
+        val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
+        /* the pending flag is always calculated */
+        if (tpm_tis_check_request_use_except(s, locty)) {
+            val |= TPM_TIS_ACCESS_PENDING_REQUEST;
+        }
+        val |= !s->be_driver->ops->get_tpm_established_flag(s->be_driver);
+        break;
+    case TPM_TIS_REG_INT_ENABLE:
+        val = tis->loc[locty].inte;
+        break;
+    case TPM_TIS_REG_INT_VECTOR:
+        val = tis->irq_num;
+        break;
+    case TPM_TIS_REG_INT_STATUS:
+        val = tis->loc[locty].ints;
+        break;
+    case TPM_TIS_REG_INTF_CAPABILITY:
+        val = TPM_TIS_CAPABILITIES_SUPPORTED;
+        break;
+    case TPM_TIS_REG_STS:
+        if (tis->active_locty == locty) {
+            if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
+                val = TPM_TIS_BURST_COUNT(
+                       tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
+                       - tis->loc[locty].r_offset) | tis->loc[locty].sts;
+            } else {
+                avail = tis->loc[locty].w_buffer.size
+                        - tis->loc[locty].w_offset;
+                /*
+                 * byte-sized reads should not return 0x00 for 0x100
+                 * available bytes.
+                 */
+                if (size == 1 && avail > 0xff) {
+                    avail = 0xff;
+                }
+                val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
+            }
+        }
+        break;
+    case TPM_TIS_REG_DATA_FIFO:
+        if (tis->active_locty == locty) {
+            switch (tis->loc[locty].state) {
+            case TPM_TIS_STATE_COMPLETION:
+                val = tpm_tis_data_read(s, locty);
+                break;
+            default:
+                val = TPM_TIS_NO_DATA_BYTE;
+                break;
+            }
+        }
+        break;
+    case TPM_TIS_REG_DID_VID:
+        val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
+        break;
+    case TPM_TIS_REG_RID:
+        val = TPM_TIS_TPM_RID;
+        break;
+#ifdef DEBUG_TIS
+    case TPM_TIS_REG_DEBUG:
+        tpm_tis_dump_state(opaque, addr);
+        break;
+#endif
+    }
+
+    if (shift) {
+        val >>= shift;
+    }
+
+    DPRINTF("tpm_tis:  read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
+
+    return val;
+}
+
+/*
+ * Write a value to a register of the TIS interface
+ * See specs pages 33-63 for description of the registers
+ */
+static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
+                                      uint64_t val, unsigned size,
+                                      bool hw_access)
+{
+    TPMState *s = opaque;
+    TPMTISEmuState *tis = &s->s.tis;
+    uint16_t off = addr & 0xfff;
+    uint8_t locty = tpm_tis_locality_from_addr(addr);
+    uint8_t active_locty, l;
+    int c, set_new_locty = 1;
+    uint16_t len;
+
+    DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
+
+    if (locty == 4 && !hw_access) {
+        DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
+        return;
+    }
+
+    if (s->be_driver->ops->had_startup_error(s->be_driver)) {
+        return;
+    }
+
+    switch (off) {
+    case TPM_TIS_REG_ACCESS:
+
+        if ((val & TPM_TIS_ACCESS_SEIZE)) {
+            val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
+                     TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+        }
+
+        active_locty = tis->active_locty;
+
+        if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
+            /* give up locality if currently owned */
+            if (tis->active_locty == locty) {
+                DPRINTF("tpm_tis: Releasing locality %d\n", locty);
+
+                uint8_t newlocty = TPM_TIS_NO_LOCALITY;
+                /* anybody wants the locality ? */
+                for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
+                    if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
+                        DPRINTF("tpm_tis: Locality %d requests use.\n", c);
+                        newlocty = c;
+                        break;
+                    }
+                }
+                DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
+                        "Next active locality: %d\n",
+                        newlocty);
+
+                if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
+                    set_new_locty = 0;
+                    tpm_tis_prep_abort(s, locty, newlocty);
+                } else {
+                    active_locty = TPM_TIS_NO_LOCALITY;
+                }
+            } else {
+                /* not currently the owner; clear a pending request */
+                tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
+            }
+        }
+
+        if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
+            tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
+        }
+
+        if ((val & TPM_TIS_ACCESS_SEIZE)) {
+            /*
+             * allow seize if a locality is active and the requesting
+             * locality is higher than the one that's active
+             * OR
+             * allow seize for requesting locality if no locality is
+             * active
+             */
+            while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
+                    locty > tis->active_locty) ||
+                    !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
+                bool higher_seize = FALSE;
+
+                /* already a pending SEIZE ? */
+                if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
+                    break;
+                }
+
+                /* check for ongoing seize by a higher locality */
+                for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
+                    if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
+                        higher_seize = TRUE;
+                        break;
+                    }
+                }
+
+                if (higher_seize) {
+                    break;
+                }
+
+                /* cancel any seize by a lower locality */
+                for (l = 0; l < locty - 1; l++) {
+                    tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
+                }
+
+                tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
+                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
+                        "Locality %d seized from locality %d\n",
+                        locty, tis->active_locty);
+                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
+                set_new_locty = 0;
+                tpm_tis_prep_abort(s, tis->active_locty, locty);
+                break;
+            }
+        }
+
+        if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
+            if (tis->active_locty != locty) {
+                if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
+                    tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
+                } else {
+                    /* no locality active -> make this one active now */
+                    active_locty = locty;
+                }
+            }
+        }
+
+        if (set_new_locty) {
+            tpm_tis_new_active_locality(s, active_locty);
+        }
+
+        break;
+    case TPM_TIS_REG_INT_ENABLE:
+        if (tis->active_locty != locty) {
+            break;
+        }
+
+        tis->loc[locty].inte = (val & (TPM_TIS_INT_ENABLED |
+                                       TPM_TIS_INT_POLARITY_MASK |
+                                       TPM_TIS_INTERRUPTS_SUPPORTED));
+        break;
+    case TPM_TIS_REG_INT_VECTOR:
+        /* hard wired -- ignore */
+        break;
+    case TPM_TIS_REG_INT_STATUS:
+        if (tis->active_locty != locty) {
+            break;
+        }
+
+        /* clearing of interrupt flags */
+        if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
+            (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
+            tis->loc[locty].ints &= ~val;
+            if (tis->loc[locty].ints == 0) {
+                qemu_irq_lower(tis->irq);
+                DPRINTF("tpm_tis: Lowering IRQ\n");
+            }
+        }
+        tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
+        break;
+    case TPM_TIS_REG_STS:
+        if (tis->active_locty != locty) {
+            break;
+        }
+
+        val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
+                TPM_TIS_STS_RESPONSE_RETRY);
+
+        if (val == TPM_TIS_STS_COMMAND_READY) {
+            switch (tis->loc[locty].state) {
+
+            case TPM_TIS_STATE_READY:
+                tis->loc[locty].w_offset = 0;
+                tis->loc[locty].r_offset = 0;
+            break;
+
+            case TPM_TIS_STATE_IDLE:
+                tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
+                tis->loc[locty].state = TPM_TIS_STATE_READY;
+                tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
+            break;
+
+            case TPM_TIS_STATE_EXECUTION:
+            case TPM_TIS_STATE_RECEPTION:
+                /* abort currently running command */
+                DPRINTF("tpm_tis: %s: Initiating abort.\n",
+                        __func__);
+                tpm_tis_prep_abort(s, locty, locty);
+            break;
+
+            case TPM_TIS_STATE_COMPLETION:
+                tis->loc[locty].w_offset = 0;
+                tis->loc[locty].r_offset = 0;
+                /* shortcut to ready state with C/R set */
+                tis->loc[locty].state = TPM_TIS_STATE_READY;
+                if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
+                    tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;
+                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
+                }
+                tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
+            break;
+
+            }
+        } else if (val == TPM_TIS_STS_TPM_GO) {
+            switch (tis->loc[locty].state) {
+            case TPM_TIS_STATE_RECEPTION:
+                if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
+                    tpm_tis_tpm_send(s, locty);
+                }
+                break;
+            default:
+                /* ignore */
+                break;
+            }
+        } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
+            switch (tis->loc[locty].state) {
+            case TPM_TIS_STATE_COMPLETION:
+                tis->loc[locty].r_offset = 0;
+                tis->loc[locty].sts = TPM_TIS_STS_VALID |
+                                      TPM_TIS_STS_DATA_AVAILABLE;
+                break;
+            default:
+                /* ignore */
+                break;
+            }
+        }
+        break;
+    case TPM_TIS_REG_DATA_FIFO:
+        /* data fifo */
+        if (tis->active_locty != locty) {
+            break;
+        }
+
+        if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
+            tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
+            tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
+            /* drop the byte */
+        } else {
+            DPRINTF("tpm_tis: Byte to send to TPM: %02x\n", (uint8_t)val);
+            if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
+                tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
+                tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;
+            }
+
+            if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
+                if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
+                    tis->loc[locty].w_buffer.
+                        buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
+                } else {
+                    tis->loc[locty].sts = TPM_TIS_STS_VALID;
+                }
+            }
+
+            /* check for complete packet */
+            if (tis->loc[locty].w_offset > 5 &&
+                (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
+                /* we have a packet length - see if we have all of it */
+#ifdef RAISE_STS_IRQ
+                bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
+#endif
+                len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
+                if (len > tis->loc[locty].w_offset) {
+                    tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
+                                          TPM_TIS_STS_VALID;
+                } else {
+                    /* packet complete */
+                    tis->loc[locty].sts = TPM_TIS_STS_VALID;
+                }
+#ifdef RAISE_STS_IRQ
+                if (needIrq) {
+                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
+                }
+#endif
+            }
+        }
+        break;
+    }
+}
+
+static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
+                               uint64_t val, unsigned size)
+{
+    return tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
+}
+
+static const MemoryRegionOps tpm_tis_memory_ops = {
+    .read = tpm_tis_mmio_read,
+    .write = tpm_tis_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+static int tpm_tis_do_startup_tpm(TPMState *s)
+{
+    return s->be_driver->ops->startup_tpm(s->be_driver);
+}
+
+/*
+ * This function is called when the machine starts, resets or due to
+ * S3 resume.
+ */
+static void tpm_tis_reset(DeviceState *dev)
+{
+    TPMState *s = TPM(dev);
+    TPMTISEmuState *tis = &s->s.tis;
+    int c;
+
+    s->be_driver->ops->reset(s->be_driver);
+
+    tis->active_locty = TPM_TIS_NO_LOCALITY;
+    tis->next_locty = TPM_TIS_NO_LOCALITY;
+    tis->aborting_locty = TPM_TIS_NO_LOCALITY;
+
+    for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
+        tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
+        tis->loc[c].sts = 0;
+        tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
+        tis->loc[c].ints = 0;
+        tis->loc[c].state = TPM_TIS_STATE_IDLE;
+
+        tis->loc[c].w_offset = 0;
+        s->be_driver->ops->realloc_buffer(&tis->loc[c].w_buffer);
+        tis->loc[c].r_offset = 0;
+        s->be_driver->ops->realloc_buffer(&tis->loc[c].r_buffer);
+    }
+
+    tpm_tis_do_startup_tpm(s);
+}
+
+static const VMStateDescription vmstate_tpm_tis = {
+    .name = "tpm",
+    .unmigratable = 1,
+};
+
+static Property tpm_tis_properties[] = {
+    DEFINE_PROP_UINT32("irq", TPMState,
+                       s.tis.irq_num, TPM_TIS_IRQ),
+    DEFINE_PROP_STRING("tpmdev", TPMState, backend),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
+{
+    TPMState *s = TPM(dev);
+    TPMTISEmuState *tis = &s->s.tis;
+
+    s->be_driver = qemu_find_tpm(s->backend);
+    if (!s->be_driver) {
+        error_setg(errp, "tpm_tis: backend driver with id %s could not be "
+                   "found", s->backend);
+        return;
+    }
+
+    s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
+
+    if (s->be_driver->ops->init(s->be_driver, s, tpm_tis_receive_cb)) {
+        error_setg(errp, "tpm_tis: backend driver with id %s could not be "
+                   "initialized", s->backend);
+        return;
+    }
+
+    if (tis->irq_num > 15) {
+        error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
+                   "of 0 to 15.\n", tis->irq_num);
+        return;
+    }
+
+    tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
+
+    isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
+}
+
+static void tpm_tis_initfn(Object *obj)
+{
+    ISADevice *dev = ISA_DEVICE(obj);
+    TPMState *s = TPM(obj);
+
+    memory_region_init_io(&s->mmio, &tpm_tis_memory_ops, s, "tpm-tis-mmio",
+                          TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
+    memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE,
+                                &s->mmio);
+}
+
+static void tpm_tis_uninitfn(Object *obj)
+{
+    TPMState *s = TPM(obj);
+
+    memory_region_del_subregion(get_system_memory(), &s->mmio);
+    memory_region_destroy(&s->mmio);
+}
+
+static void tpm_tis_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = tpm_tis_realizefn;
+    dc->props = tpm_tis_properties;
+    dc->reset = tpm_tis_reset;
+    dc->vmsd  = &vmstate_tpm_tis;
+}
+
+static const TypeInfo tpm_tis_info = {
+    .name = TYPE_TPM_TIS,
+    .parent = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(TPMState),
+    .instance_init = tpm_tis_initfn,
+    .instance_finalize = tpm_tis_uninitfn,
+    .class_init  = tpm_tis_class_init,
+};
+
+static void tpm_tis_register(void)
+{
+    type_register_static(&tpm_tis_info);
+    tpm_register_model(TPM_MODEL_TPM_TIS);
+}
+
+type_init(tpm_tis_register)
diff --git a/tpm/tpm_tis.h b/tpm/tpm_tis.h
new file mode 100644
index 0000000000..0c8df80cce
--- /dev/null
+++ b/tpm/tpm_tis.h
@@ -0,0 +1,80 @@
+/*
+ * tpm_tis.h - QEMU's TPM TIS interface emulator
+ *
+ * Copyright (C) 2006, 2010-2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger <stefanb@us.ibm.com>
+ *  David Safford <safford@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Implementation of the TIS interface according to specs found at
+ * http://www.trustedcomputinggroup.org
+ *
+ */
+#ifndef TPM_TPM_TIS_H
+#define TPM_TPM_TIS_H
+
+#include "hw/isa.h"
+#include "qemu-common.h"
+
+#define TPM_TIS_ADDR_BASE           0xFED40000
+
+#define TPM_TIS_NUM_LOCALITIES      5     /* per spec */
+#define TPM_TIS_LOCALITY_SHIFT      12
+#define TPM_TIS_NO_LOCALITY         0xff
+
+#define TPM_TIS_IS_VALID_LOCTY(x)   ((x) < TPM_TIS_NUM_LOCALITIES)
+
+#define TPM_TIS_IRQ                 5
+
+#define TPM_TIS_BUFFER_MAX          4096
+
+#define TYPE_TPM_TIS                "tpm-tis"
+
+
+typedef struct TPMSizedBuffer {
+    uint32_t size;
+    uint8_t  *buffer;
+} TPMSizedBuffer;
+
+typedef enum {
+    TPM_TIS_STATE_IDLE = 0,
+    TPM_TIS_STATE_READY,
+    TPM_TIS_STATE_COMPLETION,
+    TPM_TIS_STATE_EXECUTION,
+    TPM_TIS_STATE_RECEPTION,
+} TPMTISState;
+
+/* locality data  -- all fields are persisted */
+typedef struct TPMLocality {
+    TPMTISState state;
+    uint8_t access;
+    uint8_t sts;
+    uint32_t inte;
+    uint32_t ints;
+
+    uint16_t w_offset;
+    uint16_t r_offset;
+    TPMSizedBuffer w_buffer;
+    TPMSizedBuffer r_buffer;
+} TPMLocality;
+
+typedef struct TPMTISEmuState {
+    QEMUBH *bh;
+    uint32_t offset;
+    uint8_t buf[TPM_TIS_BUFFER_MAX];
+
+    uint8_t active_locty;
+    uint8_t aborting_locty;
+    uint8_t next_locty;
+
+    TPMLocality loc[TPM_TIS_NUM_LOCALITIES];
+
+    qemu_irq irq;
+    uint32_t irq_num;
+} TPMTISEmuState;
+
+#endif /* TPM_TPM_TIS_H */
diff --git a/trace-events b/trace-events
index 8389d83568..d6a847d18a 100644
--- a/trace-events
+++ b/trace-events
@@ -473,6 +473,7 @@ scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d"
 
 # vl.c
 vm_state_notify(int running, int reason) "running %d reason %d"
+load_file(const char *name, const char *path) "name %s location %s"
 
 # block/qcow2.c
 qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d"
diff --git a/translate-all.c b/translate-all.c
index 90ea002935..1f3237e60e 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1077,8 +1077,8 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
             tb_phys_invalidate(tb, -1);
             if (cpu != NULL) {
                 cpu->current_tb = saved_tb;
-                if (env && env->interrupt_request && cpu->current_tb) {
-                    cpu_interrupt(env, env->interrupt_request);
+                if (cpu->interrupt_request && cpu->current_tb) {
+                    cpu_interrupt(cpu, cpu->interrupt_request);
                 }
             }
         }
@@ -1382,13 +1382,13 @@ void tb_check_watchpoint(CPUArchState *env)
 
 #ifndef CONFIG_USER_ONLY
 /* mask must never be zero, except for A20 change call */
-static void tcg_handle_interrupt(CPUArchState *env, int mask)
+static void tcg_handle_interrupt(CPUState *cpu, int mask)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
+    CPUArchState *env = cpu->env_ptr;
     int old_mask;
 
-    old_mask = env->interrupt_request;
-    env->interrupt_request |= mask;
+    old_mask = cpu->interrupt_request;
+    cpu->interrupt_request |= mask;
 
     /*
      * If called from iothread context, wake the target cpu in
@@ -1552,11 +1552,9 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
 
 #else /* CONFIG_USER_ONLY */
 
-void cpu_interrupt(CPUArchState *env, int mask)
+void cpu_interrupt(CPUState *cpu, int mask)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
-
-    env->interrupt_request |= mask;
+    cpu->interrupt_request |= mask;
     cpu->tcg_exit_req = 1;
 }
 
diff --git a/ui/console.c b/ui/console.c
index 83a6fa3969..27e87f8879 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1537,22 +1537,26 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         chr->init(chr);
 }
 
-static CharDriverState *text_console_init(QemuOpts *opts)
+static CharDriverState *text_console_init(ChardevVC *vc)
 {
     CharDriverState *chr;
     QemuConsole *s;
-    unsigned width;
-    unsigned height;
+    unsigned width = 0;
+    unsigned height = 0;
 
     chr = g_malloc0(sizeof(CharDriverState));
 
-    width = qemu_opt_get_number(opts, "width", 0);
-    if (width == 0)
-        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
+    if (vc->has_width) {
+        width = vc->width;
+    } else if (vc->has_cols) {
+        width = vc->cols * FONT_WIDTH;
+    }
 
-    height = qemu_opt_get_number(opts, "height", 0);
-    if (height == 0)
-        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
+    if (vc->has_height) {
+        height = vc->height;
+    } else if (vc->has_rows) {
+        height = vc->rows * FONT_HEIGHT;
+    }
 
     if (width == 0 || height == 0) {
         s = new_console(NULL, TEXT_CONSOLE);
@@ -1575,9 +1579,9 @@ static CharDriverState *text_console_init(QemuOpts *opts)
 
 static VcHandler *vc_handler = text_console_init;
 
-CharDriverState *vc_init(QemuOpts *opts)
+CharDriverState *vc_init(ChardevVC *vc)
 {
-    return vc_handler(opts);
+    return vc_handler(vc);
 }
 
 void register_vc_handler(VcHandler *handler)
@@ -1740,9 +1744,42 @@ PixelFormat qemu_default_pixelformat(int bpp)
     return pf;
 }
 
+static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
+                              Error **errp)
+{
+    int val;
+
+    backend->vc = g_new0(ChardevVC, 1);
+
+    val = qemu_opt_get_number(opts, "width", 0);
+    if (val != 0) {
+        backend->vc->has_width = true;
+        backend->vc->width = val;
+    }
+
+    val = qemu_opt_get_number(opts, "height", 0);
+    if (val != 0) {
+        backend->vc->has_height = true;
+        backend->vc->height = val;
+    }
+
+    val = qemu_opt_get_number(opts, "cols", 0);
+    if (val != 0) {
+        backend->vc->has_cols = true;
+        backend->vc->cols = val;
+    }
+
+    val = qemu_opt_get_number(opts, "rows", 0);
+    if (val != 0) {
+        backend->vc->has_rows = true;
+        backend->vc->rows = val;
+    }
+}
+
 static void register_types(void)
 {
-    register_char_driver("vc", text_console_init);
+    register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
+                              qemu_chr_parse_vc);
 }
 
 type_init(register_types);
diff --git a/ui/gtk.c b/ui/gtk.c
index 544593e90d..794dab15b1 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -991,7 +991,7 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 static int nb_vcs;
 static CharDriverState *vcs[MAX_VCS];
 
-static CharDriverState *gd_vc_handler(QemuOpts *opts)
+static CharDriverState *gd_vc_handler(ChardevVC *unused)
 {
     CharDriverState *chr;
 
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 3f122965ad..83e4e08e85 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -949,6 +949,31 @@ int socket_listen(SocketAddress *addr, Error **errp)
     return fd;
 }
 
+int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
+{
+    QemuOpts *opts;
+    int fd;
+
+    opts = qemu_opts_create_nofail(&dummy_opts);
+    switch (remote->kind) {
+    case SOCKET_ADDRESS_KIND_INET:
+        qemu_opt_set(opts, "host", remote->inet->host);
+        qemu_opt_set(opts, "port", remote->inet->port);
+        if (local) {
+            qemu_opt_set(opts, "localaddr", local->inet->host);
+            qemu_opt_set(opts, "localport", local->inet->port);
+        }
+        fd = inet_dgram_opts(opts, errp);
+        break;
+
+    default:
+        error_setg(errp, "socket type unsupported for datagram");
+        return -1;
+    }
+    qemu_opts_del(opts);
+    return fd;
+}
+
 #ifdef _WIN32
 static void socket_cleanup(void)
 {
diff --git a/vl.c b/vl.c
index 154f7bae6a..a621aec0a4 100644
--- a/vl.c
+++ b/vl.c
@@ -139,6 +139,7 @@ int main(int argc, char **argv)
 #include "sysemu/blockdev.h"
 #include "hw/block-common.h"
 #include "migration/block.h"
+#include "tpm/tpm.h"
 #include "sysemu/dma.h"
 #include "audio/audio.h"
 #include "migration/migration.h"
@@ -178,7 +179,8 @@ int main(int argc, char **argv)
 #define MAX_VIRTIO_CONSOLES 1
 #define MAX_SCLP_CONSOLES 1
 
-static const char *data_dir;
+static const char *data_dir[16];
+static int data_dir_idx;
 const char *bios_name = NULL;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 DisplayType display_type = DT_DEFAULT;
@@ -491,6 +493,30 @@ static QemuOptsList qemu_object_opts = {
     },
 };
 
+static QemuOptsList qemu_tpmdev_opts = {
+    .name = "tpmdev",
+    .implied_opt_name = "type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_tpmdev_opts.head),
+    .desc = {
+        {
+            .name = "type",
+            .type = QEMU_OPT_STRING,
+            .help = "Type of TPM backend",
+        },
+        {
+            .name = "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 */ }
+    },
+};
+
 const char *qemu_get_vm_name(void)
 {
     return qemu_name;
@@ -2251,14 +2277,16 @@ static int balloon_parse(const char *arg)
 
 char *qemu_find_file(int type, const char *name)
 {
-    int len;
+    int i;
     const char *subdir;
     char *buf;
 
     /* Try the name as a straight path first */
     if (access(name, R_OK) == 0) {
+        trace_load_file(name, name);
         return g_strdup(name);
     }
+
     switch (type) {
     case QEMU_FILE_TYPE_BIOS:
         subdir = "";
@@ -2269,14 +2297,16 @@ char *qemu_find_file(int type, const char *name)
     default:
         abort();
     }
-    len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
-    buf = g_malloc0(len);
-    snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
-    if (access(buf, R_OK)) {
+
+    for (i = 0; i < data_dir_idx; i++) {
+        buf = g_strdup_printf("%s/%s%s", data_dir[i], subdir, name);
+        if (access(buf, R_OK) == 0) {
+            trace_load_file(name, buf);
+            return buf;
+        }
         g_free(buf);
-        return NULL;
     }
-    return buf;
+    return NULL;
 }
 
 static int device_help_func(QemuOpts *opts, void *opaque)
@@ -2868,6 +2898,7 @@ int main(int argc, char **argv, char **envp)
     qemu_add_opts(&qemu_sandbox_opts);
     qemu_add_opts(&qemu_add_fd_opts);
     qemu_add_opts(&qemu_object_opts);
+    qemu_add_opts(&qemu_tpmdev_opts);
 
     runstate_init();
 
@@ -3231,6 +3262,13 @@ int main(int argc, char **argv, char **envp)
                 }
                 break;
             }
+#ifdef CONFIG_TPM
+            case QEMU_OPTION_tpmdev:
+                if (tpm_config_parse(qemu_find_opts("tpmdev"), optarg) < 0) {
+                    exit(1);
+                }
+                break;
+#endif
             case QEMU_OPTION_mempath:
                 mem_path = optarg;
                 break;
@@ -3252,7 +3290,9 @@ int main(int argc, char **argv, char **envp)
                 add_device_config(DEV_GDB, optarg);
                 break;
             case QEMU_OPTION_L:
-                data_dir = optarg;
+                if (data_dir_idx < ARRAY_SIZE(data_dir)) {
+                    data_dir[data_dir_idx++] = optarg;
+                }
                 break;
             case QEMU_OPTION_bios:
                 bios_name = optarg;
@@ -3892,12 +3932,15 @@ int main(int argc, char **argv, char **envp)
 
     /* If no data_dir is specified then try to find it relative to the
        executable path.  */
-    if (!data_dir) {
-        data_dir = os_find_datadir(argv[0]);
+    if (data_dir_idx < ARRAY_SIZE(data_dir)) {
+        data_dir[data_dir_idx] = os_find_datadir(argv[0]);
+        if (data_dir[data_dir_idx] != NULL) {
+            data_dir_idx++;
+        }
     }
     /* If all else fails use the install path specified when building. */
-    if (!data_dir) {
-        data_dir = CONFIG_QEMU_DATADIR;
+    if (data_dir_idx < ARRAY_SIZE(data_dir)) {
+        data_dir[data_dir_idx++] = CONFIG_QEMU_DATADIR;
     }
 
     /*
@@ -4108,6 +4151,12 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+#ifdef CONFIG_TPM
+    if (tpm_init() < 0) {
+        exit(1);
+    }
+#endif
+
     /* init the bluetooth world */
     if (foreach_device_config(DEV_BT, bt_parse))
         exit(1);
@@ -4353,6 +4402,9 @@ int main(int argc, char **argv, char **envp)
     bdrv_close_all();
     pause_all_vcpus();
     res_free();
+#ifdef CONFIG_TPM
+    tpm_cleanup();
+#endif
 
     return 0;
 }
diff --git a/xen-all.c b/xen-all.c
index 110f958a53..8c05843faf 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -578,16 +578,18 @@ void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
 
 static void xen_reset_vcpu(void *opaque)
 {
-    CPUArchState *env = opaque;
+    CPUState *cpu = opaque;
 
-    env->halted = 1;
+    cpu->halted = 1;
 }
 
 void xen_vcpu_init(void)
 {
     if (first_cpu != NULL) {
-        qemu_register_reset(xen_reset_vcpu, first_cpu);
-        xen_reset_vcpu(first_cpu);
+        CPUState *cpu = ENV_GET_CPU(first_cpu);
+
+        qemu_register_reset(xen_reset_vcpu, cpu);
+        xen_reset_vcpu(cpu);
     }
     /* if rtc_clock is left to default (host_clock), disable it */
     if (rtc_clock == host_clock) {