Merge remote-tracking branch 'remotes/afaerber/tags/ppc-for-2.0' into staging

PowerPC queue for 2.0

* Fixes for -device VGA

# gpg: Signature made Thu 13 Mar 2014 19:57:12 GMT using RSA key ID 3E7E013F
# gpg: Good signature from "Andreas Färber <afaerber@suse.de>"
# gpg:                 aka "Andreas Färber <afaerber@suse.com>"

* remotes/afaerber/tags/ppc-for-2.0:
  spapr: Fix return value of vga initialization
  Fix vga_interface_type for command line argument '-device VGA'

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/bsd-user/main.c b/bsd-user/main.c
index f9246aa..f81ba55 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -1000,7 +1000,7 @@
     memset(ts, 0, sizeof(TaskState));
     init_task_state(ts);
     ts->info = info;
-    env->opaque = ts;
+    cpu->opaque = ts;
 
 #if defined(TARGET_I386)
     cpu_x86_set_cpl(env, 3);
diff --git a/cpu-exec.c b/cpu-exec.c
index 1b0f617..0914d3c 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -23,29 +23,22 @@
 #include "qemu/atomic.h"
 #include "sysemu/qtest.h"
 
-bool qemu_cpu_has_work(CPUState *cpu)
+void cpu_loop_exit(CPUState *cpu)
 {
-    return cpu_has_work(cpu);
-}
-
-void cpu_loop_exit(CPUArchState *env)
-{
-    CPUState *cpu = ENV_GET_CPU(env);
-
     cpu->current_tb = NULL;
-    siglongjmp(env->jmp_env, 1);
+    siglongjmp(cpu->jmp_env, 1);
 }
 
 /* exit the current TB from a signal handler. The host registers are
    restored in a state compatible with the CPU emulator
  */
 #if defined(CONFIG_SOFTMMU)
-void cpu_resume_from_signal(CPUArchState *env, void *puc)
+void cpu_resume_from_signal(CPUState *cpu, void *puc)
 {
     /* XXX: restore cpu registers saved in host registers */
 
-    env->exception_index = -1;
-    siglongjmp(env->jmp_env, 1);
+    cpu->exception_index = -1;
+    siglongjmp(cpu->jmp_env, 1);
 }
 #endif
 
@@ -108,7 +101,7 @@
     if (max_cycles > CF_COUNT_MASK)
         max_cycles = CF_COUNT_MASK;
 
-    tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
+    tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
                      max_cycles);
     cpu->current_tb = tb;
     /* execute the generated code */
@@ -123,6 +116,7 @@
                                       target_ulong cs_base,
                                       uint64_t flags)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
     TranslationBlock *tb, **ptb1;
     unsigned int h;
     tb_page_addr_t phys_pc, phys_page1;
@@ -160,7 +154,7 @@
     }
  not_found:
    /* if no translated code available, then translate it now */
-    tb = tb_gen_code(env, pc, cs_base, flags, 0);
+    tb = tb_gen_code(cpu, pc, cs_base, flags, 0);
 
  found:
     /* Move the last found TB to the head of the list */
@@ -170,12 +164,13 @@
         tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
     }
     /* we add the TB in the virtual pc hash table */
-    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
+    cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
     return tb;
 }
 
 static inline TranslationBlock *tb_find_fast(CPUArchState *env)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
     TranslationBlock *tb;
     target_ulong cs_base, pc;
     int flags;
@@ -184,7 +179,7 @@
        always be the same before a given translated block
        is executed. */
     cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
-    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
+    tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
     if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                  tb->flags != flags)) {
         tb = tb_find_slow(env, pc, cs_base, flags);
@@ -201,10 +196,11 @@
 
 static void cpu_handle_debug_exception(CPUArchState *env)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
     CPUWatchpoint *wp;
 
-    if (!env->watchpoint_hit) {
-        QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+    if (!cpu->watchpoint_hit) {
+        QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
             wp->flags &= ~BP_WATCHPOINT_HIT;
         }
     }
@@ -283,16 +279,16 @@
 #else
 #error unsupported target CPU
 #endif
-    env->exception_index = -1;
+    cpu->exception_index = -1;
 
     /* prepare setjmp context for exception handling */
     for(;;) {
-        if (sigsetjmp(env->jmp_env, 0) == 0) {
+        if (sigsetjmp(cpu->jmp_env, 0) == 0) {
             /* if an exception is pending, we execute it here */
-            if (env->exception_index >= 0) {
-                if (env->exception_index >= EXCP_INTERRUPT) {
+            if (cpu->exception_index >= 0) {
+                if (cpu->exception_index >= EXCP_INTERRUPT) {
                     /* exit request from the cpu execution loop */
-                    ret = env->exception_index;
+                    ret = cpu->exception_index;
                     if (ret == EXCP_DEBUG) {
                         cpu_handle_debug_exception(env);
                     }
@@ -305,11 +301,11 @@
 #if defined(TARGET_I386)
                     cc->do_interrupt(cpu);
 #endif
-                    ret = env->exception_index;
+                    ret = cpu->exception_index;
                     break;
 #else
                     cc->do_interrupt(cpu);
-                    env->exception_index = -1;
+                    cpu->exception_index = -1;
 #endif
                 }
             }
@@ -324,8 +320,8 @@
                     }
                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                         cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
-                        env->exception_index = EXCP_DEBUG;
-                        cpu_loop_exit(env);
+                        cpu->exception_index = EXCP_DEBUG;
+                        cpu_loop_exit(cpu);
                     }
 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
@@ -333,8 +329,8 @@
                     if (interrupt_request & CPU_INTERRUPT_HALT) {
                         cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
                         cpu->halted = 1;
-                        env->exception_index = EXCP_HLT;
-                        cpu_loop_exit(env);
+                        cpu->exception_index = EXCP_HLT;
+                        cpu_loop_exit(cpu);
                     }
 #endif
 #if defined(TARGET_I386)
@@ -348,8 +344,8 @@
                             cpu_svm_check_intercept_param(env, SVM_EXIT_INIT,
                                                           0);
                             do_cpu_init(x86_cpu);
-                            env->exception_index = EXCP_HALTED;
-                            cpu_loop_exit(env);
+                            cpu->exception_index = EXCP_HALTED;
+                            cpu_loop_exit(cpu);
                     } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
                             do_cpu_sipi(x86_cpu);
                     } else if (env->hflags2 & HF2_GIF_MASK) {
@@ -420,7 +416,7 @@
 #elif defined(TARGET_LM32)
                     if ((interrupt_request & CPU_INTERRUPT_HARD)
                         && (env->ie & IE_IE)) {
-                        env->exception_index = EXCP_IRQ;
+                        cpu->exception_index = EXCP_IRQ;
                         cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
@@ -429,7 +425,7 @@
                         && (env->sregs[SR_MSR] & MSR_IE)
                         && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
                         && !(env->iflags & (D_FLAG | IMM_FLAG))) {
-                        env->exception_index = EXCP_IRQ;
+                        cpu->exception_index = EXCP_IRQ;
                         cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
@@ -437,7 +433,7 @@
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                         cpu_mips_hw_interrupts_pending(env)) {
                         /* Raise it */
-                        env->exception_index = EXCP_EXT_INTERRUPT;
+                        cpu->exception_index = EXCP_EXT_INTERRUPT;
                         env->error_code = 0;
                         cc->do_interrupt(cpu);
                         next_tb = 0;
@@ -454,7 +450,7 @@
                             idx = EXCP_TICK;
                         }
                         if (idx >= 0) {
-                            env->exception_index = idx;
+                            cpu->exception_index = idx;
                             cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
@@ -469,7 +465,7 @@
                             if (((type == TT_EXTINT) &&
                                   cpu_pil_allowed(env, pil)) ||
                                   type != TT_EXTINT) {
-                                env->exception_index = env->interrupt_index;
+                                cpu->exception_index = env->interrupt_index;
                                 cc->do_interrupt(cpu);
                                 next_tb = 0;
                             }
@@ -478,7 +474,7 @@
 #elif defined(TARGET_ARM)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
                         && !(env->daif & PSTATE_F)) {
-                        env->exception_index = EXCP_FIQ;
+                        cpu->exception_index = EXCP_FIQ;
                         cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
@@ -494,14 +490,14 @@
                     if (interrupt_request & CPU_INTERRUPT_HARD
                         && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                             || !(env->daif & PSTATE_I))) {
-                        env->exception_index = EXCP_IRQ;
+                        cpu->exception_index = EXCP_IRQ;
                         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;
+                        cpu->exception_index = UC32_EXCP_INTR;
                         cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
@@ -536,7 +532,7 @@
                             }
                         }
                         if (idx >= 0) {
-                            env->exception_index = idx;
+                            cpu->exception_index = idx;
                             env->error_code = 0;
                             cc->do_interrupt(cpu);
                             next_tb = 0;
@@ -546,7 +542,7 @@
                     if (interrupt_request & CPU_INTERRUPT_HARD
                         && (env->pregs[PR_CCS] & I_FLAG)
                         && !env->locked_irq) {
-                        env->exception_index = EXCP_IRQ;
+                        cpu->exception_index = EXCP_IRQ;
                         cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
@@ -558,7 +554,7 @@
                             m_flag_archval = M_FLAG_V32;
                         }
                         if ((env->pregs[PR_CCS] & m_flag_archval)) {
-                            env->exception_index = EXCP_NMI;
+                            cpu->exception_index = EXCP_NMI;
                             cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
@@ -572,7 +568,7 @@
                            hardware doesn't rely on this, so we
                            provide/save the vector when the interrupt is
                            first signalled.  */
-                        env->exception_index = env->pending_vector;
+                        cpu->exception_index = env->pending_vector;
                         do_interrupt_m68k_hardirq(env);
                         next_tb = 0;
                     }
@@ -584,7 +580,7 @@
                     }
 #elif defined(TARGET_XTENSA)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
-                        env->exception_index = EXC_IRQ;
+                        cpu->exception_index = EXC_IRQ;
                         cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
@@ -600,8 +596,8 @@
                 }
                 if (unlikely(cpu->exit_request)) {
                     cpu->exit_request = 0;
-                    env->exception_index = EXCP_INTERRUPT;
-                    cpu_loop_exit(env);
+                    cpu->exception_index = EXCP_INTERRUPT;
+                    cpu_loop_exit(cpu);
                 }
                 spin_lock(&tcg_ctx.tb_ctx.tb_lock);
                 tb = tb_find_fast(env);
@@ -654,25 +650,25 @@
                         /* Instruction counter expired.  */
                         int insns_left;
                         tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
-                        insns_left = env->icount_decr.u32;
-                        if (env->icount_extra && insns_left >= 0) {
+                        insns_left = cpu->icount_decr.u32;
+                        if (cpu->icount_extra && insns_left >= 0) {
                             /* Refill decrementer and continue execution.  */
-                            env->icount_extra += insns_left;
-                            if (env->icount_extra > 0xffff) {
+                            cpu->icount_extra += insns_left;
+                            if (cpu->icount_extra > 0xffff) {
                                 insns_left = 0xffff;
                             } else {
-                                insns_left = env->icount_extra;
+                                insns_left = cpu->icount_extra;
                             }
-                            env->icount_extra -= insns_left;
-                            env->icount_decr.u16.low = insns_left;
+                            cpu->icount_extra -= insns_left;
+                            cpu->icount_decr.u16.low = insns_left;
                         } else {
                             if (insns_left > 0) {
                                 /* Execute remaining instructions.  */
                                 cpu_exec_nocache(env, insns_left, tb);
                             }
-                            env->exception_index = EXCP_INTERRUPT;
+                            cpu->exception_index = EXCP_INTERRUPT;
                             next_tb = 0;
-                            cpu_loop_exit(env);
+                            cpu_loop_exit(cpu);
                         }
                         break;
                     }
diff --git a/cpus.c b/cpus.c
index b6421fd..1104d61 100644
--- a/cpus.c
+++ b/cpus.c
@@ -76,7 +76,7 @@
     if (cpu_is_stopped(cpu)) {
         return true;
     }
-    if (!cpu->halted || qemu_cpu_has_work(cpu) ||
+    if (!cpu->halted || cpu_has_work(cpu) ||
         kvm_halt_in_kernel()) {
         return false;
     }
@@ -139,11 +139,10 @@
 
     icount = qemu_icount;
     if (cpu) {
-        CPUArchState *env = cpu->env_ptr;
-        if (!can_do_io(env)) {
+        if (!cpu_can_do_io(cpu)) {
             fprintf(stderr, "Bad clock read\n");
         }
-        icount -= (env->icount_decr.u16.low + env->icount_extra);
+        icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
     }
     return qemu_icount_bias + (icount << icount_time_shift);
 }
@@ -1236,6 +1235,7 @@
 
 static int tcg_cpu_exec(CPUArchState *env)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
     int ret;
 #ifdef CONFIG_PROFILER
     int64_t ti;
@@ -1248,9 +1248,9 @@
         int64_t count;
         int64_t deadline;
         int decr;
-        qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
-        env->icount_decr.u16.low = 0;
-        env->icount_extra = 0;
+        qemu_icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
+        cpu->icount_decr.u16.low = 0;
+        cpu->icount_extra = 0;
         deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
 
         /* Maintain prior (possibly buggy) behaviour where if no deadline
@@ -1266,8 +1266,8 @@
         qemu_icount += count;
         decr = (count > 0xffff) ? 0xffff : count;
         count -= decr;
-        env->icount_decr.u16.low = decr;
-        env->icount_extra = count;
+        cpu->icount_decr.u16.low = decr;
+        cpu->icount_extra = count;
     }
     ret = cpu_exec(env);
 #ifdef CONFIG_PROFILER
@@ -1276,10 +1276,9 @@
     if (use_icount) {
         /* Fold pending instructions back into the
            instruction counter, and clear the interrupt flag.  */
-        qemu_icount -= (env->icount_decr.u16.low
-                        + env->icount_extra);
-        env->icount_decr.u32 = 0;
-        env->icount_extra = 0;
+        qemu_icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
+        cpu->icount_decr.u32 = 0;
+        cpu->icount_extra = 0;
     }
     return ret;
 }
diff --git a/cputlb.c b/cputlb.c
index 0fbaa39..7bd3573 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -46,9 +46,9 @@
  * entries from the TLB at any time, so flushing more entries than
  * required is only an efficiency issue, not a correctness issue.
  */
-void tlb_flush(CPUArchState *env, int flush_global)
+void tlb_flush(CPUState *cpu, int flush_global)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
+    CPUArchState *env = cpu->env_ptr;
 
 #if defined(DEBUG_TLB)
     printf("tlb_flush:\n");
@@ -58,7 +58,7 @@
     cpu->current_tb = NULL;
 
     memset(env->tlb_table, -1, sizeof(env->tlb_table));
-    memset(env->tb_jmp_cache, 0, sizeof(env->tb_jmp_cache));
+    memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache));
 
     env->tlb_flush_addr = -1;
     env->tlb_flush_mask = 0;
@@ -77,9 +77,9 @@
     }
 }
 
-void tlb_flush_page(CPUArchState *env, target_ulong addr)
+void tlb_flush_page(CPUState *cpu, target_ulong addr)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
+    CPUArchState *env = cpu->env_ptr;
     int i;
     int mmu_idx;
 
@@ -93,7 +93,7 @@
                TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
                env->tlb_flush_addr, env->tlb_flush_mask);
 #endif
-        tlb_flush(env, 1);
+        tlb_flush(cpu, 1);
         return;
     }
     /* must reset current TB so that interrupts cannot modify the
@@ -106,7 +106,7 @@
         tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr);
     }
 
-    tb_flush_jmp_cache(env, addr);
+    tb_flush_jmp_cache(cpu, addr);
 }
 
 /* update the TLBs so that writes to code in the virtual page 'addr'
@@ -119,7 +119,7 @@
 
 /* update the TLB so that writes in physical page 'phys_addr' are no longer
    tested for self modifying code */
-void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
+void tlb_unprotect_code_phys(CPUState *cpu, ram_addr_t ram_addr,
                              target_ulong vaddr)
 {
     cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
@@ -221,10 +221,11 @@
 /* Add a new TLB entry. At most one entry for a given virtual address
    is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
    supplied size is only used by tlb_flush_page.  */
-void tlb_set_page(CPUArchState *env, target_ulong vaddr,
+void tlb_set_page(CPUState *cpu, target_ulong vaddr,
                   hwaddr paddr, int prot,
                   int mmu_idx, target_ulong size)
 {
+    CPUArchState *env = cpu->env_ptr;
     MemoryRegionSection *section;
     unsigned int index;
     target_ulong address;
@@ -232,7 +233,6 @@
     uintptr_t addend;
     CPUTLBEntry *te;
     hwaddr iotlb, xlat, sz;
-    CPUState *cpu = ENV_GET_CPU(env);
 
     assert(size >= TARGET_PAGE_SIZE);
     if (size != TARGET_PAGE_SIZE) {
@@ -261,7 +261,7 @@
     }
 
     code_address = address;
-    iotlb = memory_region_section_get_iotlb(env, section, vaddr, paddr, xlat,
+    iotlb = memory_region_section_get_iotlb(cpu, section, vaddr, paddr, xlat,
                                             prot, &address);
 
     index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -322,7 +322,7 @@
         if (cc->do_unassigned_access) {
             cc->do_unassigned_access(cpu, addr, false, true, 0, 4);
         } else {
-            cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x"
+            cpu_abort(cpu, "Trying to execute code outside RAM or ROM at 0x"
                       TARGET_FMT_lx "\n", addr);
         }
     }
diff --git a/exec.c b/exec.c
index 31ed375..6a0bc94 100644
--- a/exec.c
+++ b/exec.c
@@ -33,6 +33,7 @@
 #include "hw/xen/xen.h"
 #include "qemu/timer.h"
 #include "qemu/config-file.h"
+#include "qemu/error-report.h"
 #include "exec/memory.h"
 #include "sysemu/dma.h"
 #include "exec/address-spaces.h"
@@ -484,8 +485,8 @@
     }
     cpu->cpu_index = cpu_index;
     cpu->numa_node = 0;
-    QTAILQ_INIT(&env->breakpoints);
-    QTAILQ_INIT(&env->watchpoints);
+    QTAILQ_INIT(&cpu->breakpoints);
+    QTAILQ_INIT(&cpu->watchpoints);
 #ifndef CONFIG_USER_ONLY
     cpu->as = &address_space_memory;
     cpu->thread_id = qemu_get_thread_id();
@@ -527,29 +528,29 @@
 #endif /* TARGET_HAS_ICE */
 
 #if defined(CONFIG_USER_ONLY)
-void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
+void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
 
 {
 }
 
-int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
+int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
                           int flags, CPUWatchpoint **watchpoint)
 {
     return -ENOSYS;
 }
 #else
 /* Add a watchpoint.  */
-int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
+int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
                           int flags, CPUWatchpoint **watchpoint)
 {
-    target_ulong len_mask = ~(len - 1);
+    vaddr len_mask = ~(len - 1);
     CPUWatchpoint *wp;
 
     /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
     if ((len & (len - 1)) || (addr & ~len_mask) ||
             len == 0 || len > TARGET_PAGE_SIZE) {
-        fprintf(stderr, "qemu: tried to set invalid watchpoint at "
-                TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
+        error_report("tried to set invalid watchpoint at %"
+                     VADDR_PRIx ", len=%" VADDR_PRIu, addr, len);
         return -EINVAL;
     }
     wp = g_malloc(sizeof(*wp));
@@ -559,12 +560,13 @@
     wp->flags = flags;
 
     /* keep all GDB-injected watchpoints in front */
-    if (flags & BP_GDB)
-        QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
-    else
-        QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
+    if (flags & BP_GDB) {
+        QTAILQ_INSERT_HEAD(&cpu->watchpoints, wp, entry);
+    } else {
+        QTAILQ_INSERT_TAIL(&cpu->watchpoints, wp, entry);
+    }
 
-    tlb_flush_page(env, addr);
+    tlb_flush_page(cpu, addr);
 
     if (watchpoint)
         *watchpoint = wp;
@@ -572,16 +574,16 @@
 }
 
 /* Remove a specific watchpoint.  */
-int cpu_watchpoint_remove(CPUArchState *env, target_ulong addr, target_ulong len,
+int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
                           int flags)
 {
-    target_ulong len_mask = ~(len - 1);
+    vaddr len_mask = ~(len - 1);
     CPUWatchpoint *wp;
 
-    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
         if (addr == wp->vaddr && len_mask == wp->len_mask
                 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
-            cpu_watchpoint_remove_by_ref(env, wp);
+            cpu_watchpoint_remove_by_ref(cpu, wp);
             return 0;
         }
     }
@@ -589,29 +591,30 @@
 }
 
 /* Remove a specific watchpoint by reference.  */
-void cpu_watchpoint_remove_by_ref(CPUArchState *env, CPUWatchpoint *watchpoint)
+void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint)
 {
-    QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
+    QTAILQ_REMOVE(&cpu->watchpoints, watchpoint, entry);
 
-    tlb_flush_page(env, watchpoint->vaddr);
+    tlb_flush_page(cpu, watchpoint->vaddr);
 
     g_free(watchpoint);
 }
 
 /* Remove all matching watchpoints.  */
-void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
+void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
 {
     CPUWatchpoint *wp, *next;
 
-    QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
-        if (wp->flags & mask)
-            cpu_watchpoint_remove_by_ref(env, wp);
+    QTAILQ_FOREACH_SAFE(wp, &cpu->watchpoints, entry, next) {
+        if (wp->flags & mask) {
+            cpu_watchpoint_remove_by_ref(cpu, wp);
+        }
     }
 }
 #endif
 
 /* Add a breakpoint.  */
-int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags,
+int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
                           CPUBreakpoint **breakpoint)
 {
 #if defined(TARGET_HAS_ICE)
@@ -624,12 +627,12 @@
 
     /* keep all GDB-injected breakpoints in front */
     if (flags & BP_GDB) {
-        QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
+        QTAILQ_INSERT_HEAD(&cpu->breakpoints, bp, entry);
     } else {
-        QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
+        QTAILQ_INSERT_TAIL(&cpu->breakpoints, bp, entry);
     }
 
-    breakpoint_invalidate(ENV_GET_CPU(env), pc);
+    breakpoint_invalidate(cpu, pc);
 
     if (breakpoint) {
         *breakpoint = bp;
@@ -641,14 +644,14 @@
 }
 
 /* Remove a specific breakpoint.  */
-int cpu_breakpoint_remove(CPUArchState *env, target_ulong pc, int flags)
+int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags)
 {
 #if defined(TARGET_HAS_ICE)
     CPUBreakpoint *bp;
 
-    QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+    QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
         if (bp->pc == pc && bp->flags == flags) {
-            cpu_breakpoint_remove_by_ref(env, bp);
+            cpu_breakpoint_remove_by_ref(cpu, bp);
             return 0;
         }
     }
@@ -659,26 +662,27 @@
 }
 
 /* Remove a specific breakpoint by reference.  */
-void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint)
+void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *breakpoint)
 {
 #if defined(TARGET_HAS_ICE)
-    QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
+    QTAILQ_REMOVE(&cpu->breakpoints, breakpoint, entry);
 
-    breakpoint_invalidate(ENV_GET_CPU(env), breakpoint->pc);
+    breakpoint_invalidate(cpu, breakpoint->pc);
 
     g_free(breakpoint);
 #endif
 }
 
 /* Remove all matching breakpoints. */
-void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
+void cpu_breakpoint_remove_all(CPUState *cpu, int mask)
 {
 #if defined(TARGET_HAS_ICE)
     CPUBreakpoint *bp, *next;
 
-    QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
-        if (bp->flags & mask)
-            cpu_breakpoint_remove_by_ref(env, bp);
+    QTAILQ_FOREACH_SAFE(bp, &cpu->breakpoints, entry, next) {
+        if (bp->flags & mask) {
+            cpu_breakpoint_remove_by_ref(cpu, bp);
+        }
     }
 #endif
 }
@@ -702,9 +706,8 @@
 #endif
 }
 
-void cpu_abort(CPUArchState *env, const char *fmt, ...)
+void cpu_abort(CPUState *cpu, const char *fmt, ...)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
     va_list ap;
     va_list ap2;
 
@@ -792,7 +795,7 @@
     in_migration = enable;
 }
 
-hwaddr memory_region_section_get_iotlb(CPUArchState *env,
+hwaddr memory_region_section_get_iotlb(CPUState *cpu,
                                        MemoryRegionSection *section,
                                        target_ulong vaddr,
                                        hwaddr paddr, hwaddr xlat,
@@ -818,7 +821,7 @@
 
     /* Make accesses to pages with watchpoints go via the
        watchpoint trap routines.  */
-    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
         if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
             /* Avoid trapping reads of pages with a write breakpoint. */
             if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
@@ -1553,7 +1556,7 @@
        flushed */
     if (!cpu_physical_memory_is_clean(ram_addr)) {
         CPUArchState *env = current_cpu->env_ptr;
-        tlb_set_dirty(env, env->mem_io_vaddr);
+        tlb_set_dirty(env, current_cpu->mem_io_vaddr);
     }
 }
 
@@ -1572,34 +1575,35 @@
 /* Generate a debug exception if a watchpoint has been hit.  */
 static void check_watchpoint(int offset, int len_mask, int flags)
 {
-    CPUArchState *env = current_cpu->env_ptr;
+    CPUState *cpu = current_cpu;
+    CPUArchState *env = cpu->env_ptr;
     target_ulong pc, cs_base;
     target_ulong vaddr;
     CPUWatchpoint *wp;
     int cpu_flags;
 
-    if (env->watchpoint_hit) {
+    if (cpu->watchpoint_hit) {
         /* 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_GET_CPU(env), CPU_INTERRUPT_DEBUG);
+        cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
         return;
     }
-    vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
-    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+    vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
+    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
         if ((vaddr == (wp->vaddr & len_mask) ||
              (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
             wp->flags |= BP_WATCHPOINT_HIT;
-            if (!env->watchpoint_hit) {
-                env->watchpoint_hit = wp;
-                tb_check_watchpoint(env);
+            if (!cpu->watchpoint_hit) {
+                cpu->watchpoint_hit = wp;
+                tb_check_watchpoint(cpu);
                 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
-                    env->exception_index = EXCP_DEBUG;
-                    cpu_loop_exit(env);
+                    cpu->exception_index = EXCP_DEBUG;
+                    cpu_loop_exit(cpu);
                 } else {
                     cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
-                    tb_gen_code(env, pc, cs_base, cpu_flags, 1);
-                    cpu_resume_from_signal(env, NULL);
+                    tb_gen_code(cpu, pc, cs_base, cpu_flags, 1);
+                    cpu_resume_from_signal(cpu, NULL);
                 }
             }
         } else {
@@ -1830,14 +1834,12 @@
        reset the modified entries */
     /* XXX: slow ! */
     CPU_FOREACH(cpu) {
-        CPUArchState *env = cpu->env_ptr;
-
         /* FIXME: Disentangle the cpu.h circular files deps so we can
            directly get the right CPU from listener.  */
         if (cpu->tcg_as_listener != listener) {
             continue;
         }
-        tlb_flush(env, 1);
+        tlb_flush(cpu, 1);
     }
 }
 
diff --git a/gdbstub.c b/gdbstub.c
index e8ab0b2..8afe0b7 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -635,7 +635,6 @@
 static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
 {
     CPUState *cpu;
-    CPUArchState *env;
     int err = 0;
 
     if (kvm_enabled()) {
@@ -646,10 +645,10 @@
     case GDB_BREAKPOINT_SW:
     case GDB_BREAKPOINT_HW:
         CPU_FOREACH(cpu) {
-            env = cpu->env_ptr;
-            err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
-            if (err)
+            err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
+            if (err) {
                 break;
+            }
         }
         return err;
 #ifndef CONFIG_USER_ONLY
@@ -657,8 +656,7 @@
     case GDB_WATCHPOINT_READ:
     case GDB_WATCHPOINT_ACCESS:
         CPU_FOREACH(cpu) {
-            env = cpu->env_ptr;
-            err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
+            err = cpu_watchpoint_insert(cpu, addr, len, xlat_gdb_type[type],
                                         NULL);
             if (err)
                 break;
@@ -673,7 +671,6 @@
 static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
 {
     CPUState *cpu;
-    CPUArchState *env;
     int err = 0;
 
     if (kvm_enabled()) {
@@ -684,10 +681,10 @@
     case GDB_BREAKPOINT_SW:
     case GDB_BREAKPOINT_HW:
         CPU_FOREACH(cpu) {
-            env = cpu->env_ptr;
-            err = cpu_breakpoint_remove(env, addr, BP_GDB);
-            if (err)
+            err = cpu_breakpoint_remove(cpu, addr, BP_GDB);
+            if (err) {
                 break;
+            }
         }
         return err;
 #ifndef CONFIG_USER_ONLY
@@ -695,8 +692,7 @@
     case GDB_WATCHPOINT_READ:
     case GDB_WATCHPOINT_ACCESS:
         CPU_FOREACH(cpu) {
-            env = cpu->env_ptr;
-            err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
+            err = cpu_watchpoint_remove(cpu, addr, len, xlat_gdb_type[type]);
             if (err)
                 break;
         }
@@ -710,7 +706,6 @@
 static void gdb_breakpoint_remove_all(void)
 {
     CPUState *cpu;
-    CPUArchState *env;
 
     if (kvm_enabled()) {
         kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
@@ -718,10 +713,9 @@
     }
 
     CPU_FOREACH(cpu) {
-        env = cpu->env_ptr;
-        cpu_breakpoint_remove_all(env, BP_GDB);
+        cpu_breakpoint_remove_all(cpu, BP_GDB);
 #ifndef CONFIG_USER_ONLY
-        cpu_watchpoint_remove_all(env, BP_GDB);
+        cpu_watchpoint_remove_all(cpu, BP_GDB);
 #endif
     }
 }
@@ -1086,8 +1080,7 @@
         }
 #ifdef CONFIG_USER_ONLY
         else if (strncmp(p, "Offsets", 7) == 0) {
-            CPUArchState *env = s->c_cpu->env_ptr;
-            TaskState *ts = env->opaque;
+            TaskState *ts = s->c_cpu->opaque;
 
             snprintf(buf, sizeof(buf),
                      "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
@@ -1205,8 +1198,8 @@
     }
     switch (state) {
     case RUN_STATE_DEBUG:
-        if (env->watchpoint_hit) {
-            switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
+        if (cpu->watchpoint_hit) {
+            switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) {
             case BP_MEM_READ:
                 type = "r";
                 break;
@@ -1220,8 +1213,8 @@
             snprintf(buf, sizeof(buf),
                      "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
                      GDB_SIGNAL_TRAP, cpu_index(cpu), type,
-                     env->watchpoint_hit->vaddr);
-            env->watchpoint_hit = NULL;
+                     (target_ulong)cpu->watchpoint_hit->vaddr);
+            cpu->watchpoint_hit = NULL;
             goto send_packet;
         }
         tb_flush(env);
@@ -1594,13 +1587,16 @@
 /* Disable gdb stub for child processes.  */
 void gdbserver_fork(CPUArchState *env)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
     GDBState *s = gdbserver_state;
-    if (gdbserver_fd < 0 || s->fd < 0)
-      return;
+
+    if (gdbserver_fd < 0 || s->fd < 0) {
+        return;
+    }
     close(s->fd);
     s->fd = -1;
-    cpu_breakpoint_remove_all(env, BP_GDB);
-    cpu_watchpoint_remove_all(env, BP_GDB);
+    cpu_breakpoint_remove_all(cpu, BP_GDB);
+    cpu_watchpoint_remove_all(cpu, BP_GDB);
 }
 #else
 static int gdb_chr_can_receive(void *opaque)
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 72025d0..a1c3d1c 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -406,7 +406,7 @@
     }
 
     if (!kvm_enabled()) {
-        cpu_restore_state(env, env->mem_io_pc);
+        cpu_restore_state(cs, cs->mem_io_pc);
         cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
                              &current_flags);
     }
@@ -448,8 +448,8 @@
 
     if (!kvm_enabled()) {
         cs->current_tb = NULL;
-        tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
-        cpu_resume_from_signal(env, NULL);
+        tb_gen_code(cs, current_pc, current_cs_base, current_flags, 1);
+        cpu_resume_from_signal(cs, NULL);
     }
 }
 
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 5e1d2d3..7930a26 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -267,6 +267,7 @@
     smbios_type1_defaults = false;
     gigabyte_align = false;
     option_rom_has_mr = true;
+    x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
 }
 
 static void pc_compat_1_6(QEMUMachineInitArgs *args)
@@ -299,7 +300,7 @@
 static void pc_compat_1_2(QEMUMachineInitArgs *args)
 {
     pc_compat_1_3(args);
-    disable_kvm_pv_eoi();
+    x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
 }
 
 static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
@@ -345,7 +346,7 @@
     has_pci_info = false;
     has_acpi_build = false;
     smbios_type1_defaults = false;
-    disable_kvm_pv_eoi();
+    x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
     enable_compat_apic_id_mode();
     pc_init1(args, 1, 0);
 }
@@ -358,7 +359,7 @@
     if (!args->cpu_model) {
         args->cpu_model = "486";
     }
-    disable_kvm_pv_eoi();
+    x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
     enable_compat_apic_id_mode();
     pc_init1(args, 0, 1);
 }
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 4b0456a..c844dc2 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -245,6 +245,7 @@
     smbios_type1_defaults = false;
     gigabyte_align = false;
     option_rom_has_mr = true;
+    x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
 }
 
 static void pc_compat_1_6(QEMUMachineInitArgs *args)
diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c
index 0c948e2..94fdffa 100644
--- a/hw/pci-host/prep.c
+++ b/hw/pci-host/prep.c
@@ -28,7 +28,9 @@
 #include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
 #include "hw/i386/pc.h"
+#include "hw/loader.h"
 #include "exec/address-spaces.h"
+#include "elf.h"
 
 #define TYPE_RAVEN_PCI_DEVICE "raven"
 #define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
@@ -38,6 +40,10 @@
 
 typedef struct RavenPCIState {
     PCIDevice dev;
+
+    uint32_t elf_machine;
+    char *bios_name;
+    MemoryRegion bios;
 } RavenPCIState;
 
 #define RAVEN_PCI_HOST_BRIDGE(obj) \
@@ -52,6 +58,8 @@
     RavenPCIState pci_dev;
 } PREPPCIState;
 
+#define BIOS_SIZE (1024 * 1024)
+
 static inline uint32_t PPC_PCIIO_config(hwaddr addr)
 {
     int i;
@@ -169,10 +177,45 @@
 
 static int raven_init(PCIDevice *d)
 {
+    RavenPCIState *s = RAVEN_PCI_DEVICE(d);
+    char *filename;
+    int bios_size = -1;
+
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x34] = 0x00; // capabilities_pointer
 
+    memory_region_init_ram(&s->bios, OBJECT(s), "bios", BIOS_SIZE);
+    memory_region_set_readonly(&s->bios, true);
+    memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
+                                &s->bios);
+    vmstate_register_ram_global(&s->bios);
+    if (s->bios_name) {
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
+        if (filename) {
+            if (s->elf_machine != EM_NONE) {
+                bios_size = load_elf(filename, NULL, NULL, NULL,
+                                     NULL, NULL, 1, s->elf_machine, 0);
+            }
+            if (bios_size < 0) {
+                bios_size = get_image_size(filename);
+                if (bios_size > 0 && bios_size <= BIOS_SIZE) {
+                    hwaddr bios_addr;
+                    bios_size = (bios_size + 0xfff) & ~0xfff;
+                    bios_addr = (uint32_t)(-BIOS_SIZE);
+                    bios_size = load_image_targphys(filename, bios_addr,
+                                                    bios_size);
+                }
+            }
+        }
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            hw_error("qemu: could not load bios image '%s'\n", s->bios_name);
+        }
+        if (filename) {
+            g_free(filename);
+        }
+    }
+
     return 0;
 }
 
@@ -212,12 +255,20 @@
     .class_init = raven_class_init,
 };
 
+static Property raven_pcihost_properties[] = {
+    DEFINE_PROP_UINT32("elf-machine", PREPPCIState, pci_dev.elf_machine,
+                       EM_NONE),
+    DEFINE_PROP_STRING("bios-name", PREPPCIState, pci_dev.bios_name),
+    DEFINE_PROP_END_OF_LIST()
+};
+
 static void raven_pcihost_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
     dc->realize = raven_pcihost_realizefn;
+    dc->props = raven_pcihost_properties;
     dc->fw_name = "pci";
 }
 
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 8a08752..d7ba25f 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -472,14 +472,13 @@
 {
     PowerPCCPU *cpu = opaque;
     CPUState *cs = CPU(cpu);
-    CPUPPCState *env = &cpu->env;
 
     cpu_reset(cs);
 
     /* Secondary CPU starts in halted state for now. Needs to change when
        implementing non-kernel boot. */
     cs->halted = 1;
-    env->exception_index = EXCP_HLT;
+    cs->exception_index = EXCP_HLT;
 }
 
 static void ppce500_cpu_reset(void *opaque)
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index ca520e8..54ba59e 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -44,7 +44,7 @@
 ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
                                 uint32_t flags)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     ram_addr_t bdloc;
     int i, n;
 
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index 78b23fa..f9fdc8c 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -117,7 +117,7 @@
     mmubooke_create_initial_mapping(env, 0, map_start, map_size);
 
     cpu->halted = 0;
-    env->exception_index = -1;
+    cpu->exception_index = -1;
     cpu->stopped = false;
     qemu_cpu_kick(cpu);
 }
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 9f8538c..81e13cb 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -456,7 +456,6 @@
     MemoryRegion *sysmem = get_system_memory();
     PowerPCCPU *cpu = NULL;
     CPUPPCState *env = NULL;
-    char *filename;
     nvram_t nvram;
     M48t59State *m48t59;
     MemoryRegion *PPC_io_memory = g_new(MemoryRegion, 1);
@@ -464,9 +463,8 @@
 #if 0
     MemoryRegion *xcsr = g_new(MemoryRegion, 1);
 #endif
-    int linux_boot, i, nb_nics1, bios_size;
+    int linux_boot, i, nb_nics1;
     MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *bios = g_new(MemoryRegion, 1);
     uint32_t kernel_base, initrd_base;
     long kernel_size, initrd_size;
     DeviceState *dev;
@@ -509,43 +507,6 @@
     vmstate_register_ram_global(ram);
     memory_region_add_subregion(sysmem, 0, ram);
 
-    /* allocate and load BIOS */
-    memory_region_init_ram(bios, NULL, "ppc_prep.bios", BIOS_SIZE);
-    memory_region_set_readonly(bios, true);
-    memory_region_add_subregion(sysmem, (uint32_t)(-BIOS_SIZE), bios);
-    vmstate_register_ram_global(bios);
-    if (bios_name == NULL)
-        bios_name = BIOS_FILENAME;
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        bios_size = load_elf(filename, NULL, NULL, NULL,
-                             NULL, NULL, 1, ELF_MACHINE, 0);
-        if (bios_size < 0) {
-            bios_size = get_image_size(filename);
-            if (bios_size > 0 && bios_size <= BIOS_SIZE) {
-                hwaddr bios_addr;
-                bios_size = (bios_size + 0xfff) & ~0xfff;
-                bios_addr = (uint32_t)(-bios_size);
-                bios_size = load_image_targphys(filename, bios_addr, bios_size);
-            }
-            if (bios_size > BIOS_SIZE) {
-                fprintf(stderr, "qemu: PReP bios '%s' is too large (0x%x)\n",
-                        bios_name, bios_size);
-                exit(1);
-            }
-        }
-    } else {
-        bios_size = -1;
-    }
-    if (bios_size < 0 && !qtest_enabled()) {
-        fprintf(stderr, "qemu: could not load PPC PReP bios '%s'\n",
-                bios_name);
-        exit(1);
-    }
-    if (filename) {
-        g_free(filename);
-    }
-
     if (linux_boot) {
         kernel_base = KERNEL_LOAD_ADDR;
         /* now we can load the kernel */
@@ -593,6 +554,11 @@
     }
 
     dev = qdev_create(NULL, "raven-pcihost");
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    qdev_prop_set_string(dev, "bios-name", bios_name);
+    qdev_prop_set_uint32(dev, "elf-machine", ELF_MACHINE);
     pcihost = PCI_HOST_BRIDGE(dev);
     object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
     qdev_init_nofail(dev);
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index d918780..e999bba 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -356,7 +356,7 @@
 
 static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     uint16_t size;
     uint8_t tmp;
 
@@ -406,7 +406,7 @@
 
 static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     uint32_t size;
 
     if (addr == 0) {
@@ -442,7 +442,7 @@
 
 static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     uint32_t size;
 
     if (addr == 0) {
@@ -529,7 +529,7 @@
     hreg_compute_hflags(env);
     if (!cpu_has_work(cs)) {
         cs->halted = 1;
-        env->exception_index = EXCP_HLT;
+        cs->exception_index = EXCP_HLT;
         cs->exit_request = 1;
     }
     return H_SUCCESS;
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index 0f03fd1..aef2003 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -135,25 +135,23 @@
 void s390_add_running_cpu(S390CPU *cpu)
 {
     CPUState *cs = CPU(cpu);
-    CPUS390XState *env = &cpu->env;
 
     if (cs->halted) {
         s390_running_cpus++;
         cs->halted = 0;
-        env->exception_index = -1;
+        cs->exception_index = -1;
     }
 }
 
 unsigned s390_del_running_cpu(S390CPU *cpu)
 {
     CPUState *cs = CPU(cpu);
-    CPUS390XState *env = &cpu->env;
 
     if (cs->halted == 0) {
         assert(s390_running_cpus >= 1);
         s390_running_cpus--;
         cs->halted = 1;
-        env->exception_index = EXCP_HLT;
+        cs->exception_index = EXCP_HLT;
     }
     return s390_running_cpus;
 }
@@ -196,7 +194,7 @@
 
         ipi_states[i] = cpu;
         cs->halted = 1;
-        cpu->env.exception_index = EXCP_HLT;
+        cs->exception_index = EXCP_HLT;
         cpu->env.storage_keys = storage_keys;
     }
 }
diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c
index 1439ba4..4a39357 100644
--- a/hw/sh4/sh7750.c
+++ b/hw/sh4/sh7750.c
@@ -416,7 +416,7 @@
     case SH7750_PTEH_A7:
         /* If asid changes, clear all registered tlb entries. */
         if ((s->cpu->env.pteh & 0xff) != (mem_value & 0xff)) {
-            tlb_flush(&s->cpu->env, 1);
+            tlb_flush(CPU(s->cpu), 1);
         }
         s->cpu->env.pteh = mem_value;
         return;
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 4cb4b4a..fb649a4 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -360,9 +360,6 @@
 
 CPUArchState *cpu_copy(CPUArchState *env);
 
-void QEMU_NORETURN cpu_abort(CPUArchState *env, const char *fmt, ...)
-    GCC_FMT_ATTR(2, 3);
-
 /* Flags for use in ENV->INTERRUPT_PENDING.
 
    The numbers assigned here are non-sequential in order to preserve
@@ -413,27 +410,6 @@
      | CPU_INTERRUPT_TGT_EXT_3   \
      | CPU_INTERRUPT_TGT_EXT_4)
 
-/* Breakpoint/watchpoint flags */
-#define BP_MEM_READ           0x01
-#define BP_MEM_WRITE          0x02
-#define BP_MEM_ACCESS         (BP_MEM_READ | BP_MEM_WRITE)
-#define BP_STOP_BEFORE_ACCESS 0x04
-#define BP_WATCHPOINT_HIT     0x08
-#define BP_GDB                0x10
-#define BP_CPU                0x20
-
-int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags,
-                          CPUBreakpoint **breakpoint);
-int cpu_breakpoint_remove(CPUArchState *env, target_ulong pc, int flags);
-void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint);
-void cpu_breakpoint_remove_all(CPUArchState *env, int mask);
-int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
-                          int flags, CPUWatchpoint **watchpoint);
-int cpu_watchpoint_remove(CPUArchState *env, target_ulong addr,
-                          target_ulong len, int flags);
-void cpu_watchpoint_remove_by_ref(CPUArchState *env, CPUWatchpoint *watchpoint);
-void cpu_watchpoint_remove_all(CPUArchState *env, int mask);
-
 #if !defined(CONFIG_USER_ONLY)
 
 /* memory API */
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 66a3d46..2dd6206 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -24,7 +24,6 @@
 #endif
 
 #include "config.h"
-#include <setjmp.h>
 #include <inttypes.h>
 #include "qemu/osdep.h"
 #include "qemu/queue.h"
@@ -61,9 +60,6 @@
 #define EXCP_HALTED     0x10003 /* cpu is halted (waiting for external event) */
 #define EXCP_YIELD      0x10004 /* cpu wants to yield timeslice to another */
 
-#define TB_JMP_CACHE_BITS 12
-#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
-
 /* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
    addresses on the same page.  The top bits are the same.  This allows
    TLB invalidation to quickly clear a subset of the hash table.  */
@@ -118,66 +114,9 @@
 #endif
 
 
-#ifdef HOST_WORDS_BIGENDIAN
-typedef struct icount_decr_u16 {
-    uint16_t high;
-    uint16_t low;
-} icount_decr_u16;
-#else
-typedef struct icount_decr_u16 {
-    uint16_t low;
-    uint16_t high;
-} icount_decr_u16;
-#endif
-
-typedef struct CPUBreakpoint {
-    target_ulong pc;
-    int flags; /* BP_* */
-    QTAILQ_ENTRY(CPUBreakpoint) entry;
-} CPUBreakpoint;
-
-typedef struct CPUWatchpoint {
-    target_ulong vaddr;
-    target_ulong len_mask;
-    int flags; /* BP_* */
-    QTAILQ_ENTRY(CPUWatchpoint) entry;
-} CPUWatchpoint;
-
 #define CPU_TEMP_BUF_NLONGS 128
 #define CPU_COMMON                                                      \
     /* soft mmu support */                                              \
-    /* in order to avoid passing too many arguments to the MMIO         \
-       helpers, we store some rarely used information in the CPU        \
-       context) */                                                      \
-    uintptr_t mem_io_pc; /* host pc at which the memory was             \
-                            accessed */                                 \
-    target_ulong mem_io_vaddr; /* target virtual addr at which the      \
-                                     memory was accessed */             \
     CPU_COMMON_TLB                                                      \
-    struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];           \
-                                                                        \
-    int64_t icount_extra; /* Instructions until next timer event.  */   \
-    /* Number of cycles left, with interrupt flag in high bit.          \
-       This allows a single read-compare-cbranch-write sequence to test \
-       for both decrementer underflow and exceptions.  */               \
-    union {                                                             \
-        uint32_t u32;                                                   \
-        icount_decr_u16 u16;                                            \
-    } icount_decr;                                                      \
-    uint32_t can_do_io; /* nonzero if memory mapped IO is safe.  */     \
-                                                                        \
-    /* from this point: preserved by CPU reset */                       \
-    /* ice debug support */                                             \
-    QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints;            \
-                                                                        \
-    QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints;            \
-    CPUWatchpoint *watchpoint_hit;                                      \
-                                                                        \
-    /* Core interrupt code */                                           \
-    sigjmp_buf jmp_env;                                                 \
-    int exception_index;                                                \
-                                                                        \
-    /* user data */                                                     \
-    void *opaque;                                                       \
 
 #endif
diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h
index e21cb60..b8ecd6f 100644
--- a/include/exec/cputlb.h
+++ b/include/exec/cputlb.h
@@ -22,7 +22,7 @@
 #if !defined(CONFIG_USER_ONLY)
 /* cputlb.c */
 void tlb_protect_code(ram_addr_t ram_addr);
-void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
+void tlb_unprotect_code_phys(CPUState *cpu, ram_addr_t ram_addr,
                              target_ulong vaddr);
 void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
                            uintptr_t length);
@@ -31,12 +31,12 @@
 extern int tlb_flush_count;
 
 /* exec.c */
-void tb_flush_jmp_cache(CPUArchState *env, target_ulong addr);
+void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr);
 
 MemoryRegionSection *
 address_space_translate_for_iotlb(AddressSpace *as, hwaddr addr, hwaddr *xlat,
                                   hwaddr *plen);
-hwaddr memory_region_section_get_iotlb(CPUArchState *env,
+hwaddr memory_region_section_get_iotlb(CPUState *cpu,
                                        MemoryRegionSection *section,
                                        target_ulong vaddr,
                                        hwaddr paddr, hwaddr xlat,
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index a387922..502b7aa 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -80,16 +80,16 @@
 void cpu_gen_init(void);
 int cpu_gen_code(CPUArchState *env, struct TranslationBlock *tb,
                  int *gen_code_size_ptr);
-bool cpu_restore_state(CPUArchState *env, uintptr_t searched_pc);
+bool cpu_restore_state(CPUState *cpu, uintptr_t searched_pc);
 void page_size_init(void);
 
-void QEMU_NORETURN cpu_resume_from_signal(CPUArchState *env1, void *puc);
-void QEMU_NORETURN cpu_io_recompile(CPUArchState *env, uintptr_t retaddr);
-TranslationBlock *tb_gen_code(CPUArchState *env, 
+void QEMU_NORETURN cpu_resume_from_signal(CPUState *cpu, void *puc);
+void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
+TranslationBlock *tb_gen_code(CPUState *cpu,
                               target_ulong pc, target_ulong cs_base, int flags,
                               int cflags);
 void cpu_exec_init(CPUArchState *env);
-void QEMU_NORETURN cpu_loop_exit(CPUArchState *env1);
+void QEMU_NORETURN cpu_loop_exit(CPUState *cpu);
 int page_unprotect(target_ulong address, uintptr_t pc, void *puc);
 void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
                                    int is_cpu_write_access);
@@ -98,18 +98,18 @@
 #if !defined(CONFIG_USER_ONLY)
 void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as);
 /* cputlb.c */
-void tlb_flush_page(CPUArchState *env, target_ulong addr);
-void tlb_flush(CPUArchState *env, int flush_global);
-void tlb_set_page(CPUArchState *env, target_ulong vaddr,
+void tlb_flush_page(CPUState *cpu, target_ulong addr);
+void tlb_flush(CPUState *cpu, int flush_global);
+void tlb_set_page(CPUState *cpu, target_ulong vaddr,
                   hwaddr paddr, int prot,
                   int mmu_idx, target_ulong size);
 void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
 #else
-static inline void tlb_flush_page(CPUArchState *env, target_ulong addr)
+static inline void tlb_flush_page(CPUState *cpu, target_ulong addr)
 {
 }
 
-static inline void tlb_flush(CPUArchState *env, int flush_global)
+static inline void tlb_flush(CPUState *cpu, int flush_global)
 {
 }
 #endif
@@ -332,7 +332,7 @@
 bool io_mem_write(struct MemoryRegion *mr, hwaddr addr,
                   uint64_t value, unsigned size);
 
-void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cpu, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr);
 
 uint8_t helper_ldb_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
@@ -380,20 +380,25 @@
 /* cpu-exec.c */
 extern volatile sig_atomic_t exit_request;
 
-/* Deterministic execution requires that IO only be performed on the last
-   instruction of a TB so that interrupts take effect immediately.  */
-static inline int can_do_io(CPUArchState *env)
+/**
+ * cpu_can_do_io:
+ * @cpu: The CPU for which to check IO.
+ *
+ * Deterministic execution requires that IO only be performed on the last
+ * instruction of a TB so that interrupts take effect immediately.
+ *
+ * Returns: %true if memory-mapped IO is safe, %false otherwise.
+ */
+static inline bool cpu_can_do_io(CPUState *cpu)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
-
     if (!use_icount) {
-        return 1;
+        return true;
     }
     /* If not executing code then assume we are ok.  */
     if (cpu->current_tb == NULL) {
-        return 1;
+        return true;
     }
-    return env->can_do_io != 0;
+    return cpu->can_do_io != 0;
 }
 
 #endif
diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
index 39a6b61..da53395 100644
--- a/include/exec/gen-icount.h
+++ b/include/exec/gen-icount.h
@@ -26,13 +26,15 @@
 
     icount_label = gen_new_label();
     count = tcg_temp_local_new_i32();
-    tcg_gen_ld_i32(count, cpu_env, offsetof(CPUArchState, icount_decr.u32));
+    tcg_gen_ld_i32(count, cpu_env,
+                   -ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
     /* This is a horrid hack to allow fixing up the value later.  */
     icount_arg = tcg_ctx.gen_opparam_ptr + 1;
     tcg_gen_subi_i32(count, count, 0xdeadbeef);
 
     tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);
-    tcg_gen_st16_i32(count, cpu_env, offsetof(CPUArchState, icount_decr.u16.low));
+    tcg_gen_st16_i32(count, cpu_env,
+                     -ENV_OFFSET + offsetof(CPUState, icount_decr.u16.low));
     tcg_temp_free_i32(count);
 }
 
@@ -51,14 +53,14 @@
 static inline void gen_io_start(void)
 {
     TCGv_i32 tmp = tcg_const_i32(1);
-    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUArchState, can_do_io));
+    tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io));
     tcg_temp_free_i32(tmp);
 }
 
 static inline void gen_io_end(void)
 {
     TCGv_i32 tmp = tcg_const_i32(0);
-    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUArchState, can_do_io));
+    tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io));
     tcg_temp_free_i32(tmp);
 }
 
diff --git a/include/exec/softmmu_template.h b/include/exec/softmmu_template.h
index c14a04d..73ed7cf 100644
--- a/include/exec/softmmu_template.h
+++ b/include/exec/softmmu_template.h
@@ -126,12 +126,12 @@
     MemoryRegion *mr = iotlb_to_region(cpu->as, physaddr);
 
     physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
-    env->mem_io_pc = retaddr;
-    if (mr != &io_mem_rom && mr != &io_mem_notdirty && !can_do_io(env)) {
-        cpu_io_recompile(env, retaddr);
+    cpu->mem_io_pc = retaddr;
+    if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu_can_do_io(cpu)) {
+        cpu_io_recompile(cpu, retaddr);
     }
 
-    env->mem_io_vaddr = addr;
+    cpu->mem_io_vaddr = addr;
     io_mem_read(mr, physaddr, &val, 1 << SHIFT);
     return val;
 }
@@ -158,7 +158,7 @@
             do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         }
 #endif
-        tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        tlb_fill(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
     }
 
@@ -240,7 +240,7 @@
             do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         }
 #endif
-        tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        tlb_fill(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
     }
 
@@ -333,12 +333,12 @@
     MemoryRegion *mr = iotlb_to_region(cpu->as, physaddr);
 
     physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
-    if (mr != &io_mem_rom && mr != &io_mem_notdirty && !can_do_io(env)) {
-        cpu_io_recompile(env, retaddr);
+    if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu_can_do_io(cpu)) {
+        cpu_io_recompile(cpu, retaddr);
     }
 
-    env->mem_io_vaddr = addr;
-    env->mem_io_pc = retaddr;
+    cpu->mem_io_vaddr = addr;
+    cpu->mem_io_pc = retaddr;
     io_mem_write(mr, physaddr, val, 1 << SHIFT);
 }
 
@@ -360,7 +360,7 @@
             do_unaligned_access(env, addr, 1, mmu_idx, retaddr);
         }
 #endif
-        tlb_fill(env, addr, 1, mmu_idx, retaddr);
+        tlb_fill(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr);
         tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
     }
 
@@ -436,7 +436,7 @@
             do_unaligned_access(env, addr, 1, mmu_idx, retaddr);
         }
 #endif
-        tlb_fill(env, addr, 1, mmu_idx, retaddr);
+        tlb_fill(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr);
         tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
     }
 
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index d734be8..06ee263 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -21,6 +21,7 @@
 #define QEMU_CPU_H
 
 #include <signal.h>
+#include <setjmp.h>
 #include "hw/qdev-core.h"
 #include "exec/hwaddr.h"
 #include "qemu/queue.h"
@@ -68,8 +69,10 @@
  * CPUClass:
  * @class_by_name: Callback to map -cpu command line model name to an
  * instantiatable CPU type.
+ * @parse_features: Callback to parse command line arguments.
  * @reset: Callback to reset the #CPUState to its initial state.
  * @reset_dump_flags: #CPUDumpFlags to use for reset logging.
+ * @has_work: Callback for checking if there is work to do.
  * @do_interrupt: Callback for interrupt handling.
  * @do_unassigned_access: Callback for unassigned access handling.
  * @memory_rw_debug: Callback for GDB memory access.
@@ -81,6 +84,7 @@
  * @set_pc: Callback for setting the Program Counter register.
  * @synchronize_from_tb: Callback for synchronizing state from a TCG
  * #TranslationBlock.
+ * @handle_mmu_fault: Callback for handling an MMU fault.
  * @get_phys_page_debug: Callback for obtaining a physical address.
  * @gdb_read_register: Callback for letting GDB read a register.
  * @gdb_write_register: Callback for letting GDB write a register.
@@ -96,9 +100,11 @@
     /*< public >*/
 
     ObjectClass *(*class_by_name)(const char *cpu_model);
+    void (*parse_features)(CPUState *cpu, char *str, Error **errp);
 
     void (*reset)(CPUState *cpu);
     int reset_dump_flags;
+    bool (*has_work)(CPUState *cpu);
     void (*do_interrupt)(CPUState *cpu);
     CPUUnassignedAccess do_unassigned_access;
     int (*memory_rw_debug)(CPUState *cpu, vaddr addr,
@@ -113,6 +119,8 @@
                                Error **errp);
     void (*set_pc)(CPUState *cpu, vaddr value);
     void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
+    int (*handle_mmu_fault)(CPUState *cpu, vaddr address, int rw,
+                            int mmu_index);
     hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
     int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
     int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
@@ -131,9 +139,37 @@
     const char *gdb_core_xml_file;
 } CPUClass;
 
+#ifdef HOST_WORDS_BIGENDIAN
+typedef struct icount_decr_u16 {
+    uint16_t high;
+    uint16_t low;
+} icount_decr_u16;
+#else
+typedef struct icount_decr_u16 {
+    uint16_t low;
+    uint16_t high;
+} icount_decr_u16;
+#endif
+
+typedef struct CPUBreakpoint {
+    vaddr pc;
+    int flags; /* BP_* */
+    QTAILQ_ENTRY(CPUBreakpoint) entry;
+} CPUBreakpoint;
+
+typedef struct CPUWatchpoint {
+    vaddr vaddr;
+    vaddr len_mask;
+    int flags; /* BP_* */
+    QTAILQ_ENTRY(CPUWatchpoint) entry;
+} CPUWatchpoint;
+
 struct KVMState;
 struct kvm_run;
 
+#define TB_JMP_CACHE_BITS 12
+#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
+
 /**
  * CPUState:
  * @cpu_index: CPU index (informative).
@@ -150,12 +186,20 @@
  * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this
  *           CPU and return to its top level loop.
  * @singlestep_enabled: Flags for single-stepping.
+ * @icount_extra: Instructions until next timer event.
+ * @icount_decr: Number of cycles left, with interrupt flag in high bit.
+ * This allows a single read-compare-cbranch-write sequence to test
+ * for both decrementer underflow and exceptions.
+ * @can_do_io: Nonzero if memory-mapped IO is safe.
  * @env_ptr: Pointer to subclass-specific CPUArchState field.
  * @current_tb: Currently executing TB.
  * @gdb_regs: Additional GDB registers.
  * @gdb_num_regs: Number of total registers accessible to GDB.
  * @gdb_num_g_regs: Number of registers in GDB 'g' packets.
  * @next_cpu: Next CPU sharing TB cache.
+ * @opaque: User data.
+ * @mem_io_pc: Host Program Counter at which the memory was accessed.
+ * @mem_io_vaddr: Target virtual address at which the memory was accessed.
  * @kvm_fd: vCPU file descriptor for KVM.
  *
  * State of one CPU core or thread.
@@ -186,17 +230,34 @@
     volatile sig_atomic_t tcg_exit_req;
     uint32_t interrupt_request;
     int singlestep_enabled;
+    int64_t icount_extra;
+    sigjmp_buf jmp_env;
 
     AddressSpace *as;
     MemoryListener *tcg_as_listener;
 
     void *env_ptr; /* CPUArchState */
     struct TranslationBlock *current_tb;
+    struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];
     struct GDBRegisterState *gdb_regs;
     int gdb_num_regs;
     int gdb_num_g_regs;
     QTAILQ_ENTRY(CPUState) node;
 
+    /* ice debug support */
+    QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints;
+
+    QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints;
+    CPUWatchpoint *watchpoint_hit;
+
+    void *opaque;
+
+    /* In order to avoid passing too many arguments to the MMIO helpers,
+     * we store some rarely used information in the CPU context.
+     */
+    uintptr_t mem_io_pc;
+    vaddr mem_io_vaddr;
+
     int kvm_fd;
     bool kvm_vcpu_dirty;
     struct KVMState *kvm_state;
@@ -205,6 +266,12 @@
     /* TODO Move common fields from CPUArchState here. */
     int cpu_index; /* used by alpha TCG */
     uint32_t halted; /* used by alpha, cris, ppc TCG */
+    union {
+        uint32_t u32;
+        icount_decr_u16 u16;
+    } icount_decr;
+    uint32_t can_do_io;
+    int32_t exception_index; /* used by m68k TCG */
 };
 
 QTAILQ_HEAD(CPUTailQ, CPUState);
@@ -348,14 +415,31 @@
 ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model);
 
 /**
- * qemu_cpu_has_work:
+ * cpu_generic_init:
+ * @typename: The CPU base type.
+ * @cpu_model: The model string including optional parameters.
+ *
+ * Instantiates a CPU, processes optional parameters and realizes the CPU.
+ *
+ * Returns: A #CPUState or %NULL if an error occurred.
+ */
+CPUState *cpu_generic_init(const char *typename, const char *cpu_model);
+
+/**
+ * cpu_has_work:
  * @cpu: The vCPU to check.
  *
  * Checks whether the CPU has work to do.
  *
  * Returns: %true if the CPU has work, %false otherwise.
  */
-bool qemu_cpu_has_work(CPUState *cpu);
+static inline bool cpu_has_work(CPUState *cpu)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    g_assert(cc->has_work);
+    return cc->has_work(cpu);
+}
 
 /**
  * qemu_cpu_is_self:
@@ -511,6 +595,31 @@
  */
 void cpu_single_step(CPUState *cpu, int enabled);
 
+/* Breakpoint/watchpoint flags */
+#define BP_MEM_READ           0x01
+#define BP_MEM_WRITE          0x02
+#define BP_MEM_ACCESS         (BP_MEM_READ | BP_MEM_WRITE)
+#define BP_STOP_BEFORE_ACCESS 0x04
+#define BP_WATCHPOINT_HIT     0x08
+#define BP_GDB                0x10
+#define BP_CPU                0x20
+
+int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
+                          CPUBreakpoint **breakpoint);
+int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags);
+void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *breakpoint);
+void cpu_breakpoint_remove_all(CPUState *cpu, int mask);
+
+int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
+                          int flags, CPUWatchpoint **watchpoint);
+int cpu_watchpoint_remove(CPUState *cpu, vaddr addr,
+                          vaddr len, int flags);
+void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint);
+void cpu_watchpoint_remove_all(CPUState *cpu, int mask);
+
+void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
 #ifdef CONFIG_SOFTMMU
 extern const struct VMStateDescription vmstate_cpu_common;
 #else
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c0687e3..6bc7999 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2621,7 +2621,8 @@
 
 static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
 {
-    TaskState *ts = (TaskState *)env->opaque;
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)env);
+    TaskState *ts = (TaskState *)cpu->opaque;
     struct elf_thread_status *ets;
 
     ets = g_malloc0(sizeof (*ets));
@@ -2650,8 +2651,8 @@
                           long signr, const CPUArchState *env)
 {
 #define NUMNOTES 3
-    CPUState *cpu = NULL;
-    TaskState *ts = (TaskState *)env->opaque;
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)env);
+    TaskState *ts = (TaskState *)cpu->opaque;
     int i;
 
     info->notes = g_malloc0(NUMNOTES * sizeof (struct memelfnote));
@@ -2775,7 +2776,8 @@
  */
 static int elf_core_dump(int signr, const CPUArchState *env)
 {
-    const TaskState *ts = (const TaskState *)env->opaque;
+    const CPUState *cpu = ENV_GET_CPU((CPUArchState *)env);
+    const TaskState *ts = (const TaskState *)cpu->opaque;
     struct vm_area_struct *vma = NULL;
     char corefile[PATH_MAX];
     struct elf_note_info info;
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index f2997c2..506e837 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -89,8 +89,7 @@
 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
                               abi_ulong stringp, int push_ptr)
 {
-    CPUArchState *env = thread_cpu->env_ptr;
-    TaskState *ts = (TaskState *)env->opaque;
+    TaskState *ts = (TaskState *)thread_cpu->opaque;
     int n = sizeof(abi_ulong);
     abi_ulong envp;
     abi_ulong argv;
diff --git a/linux-user/m68k-sim.c b/linux-user/m68k-sim.c
index d5926ee..1994e40 100644
--- a/linux-user/m68k-sim.c
+++ b/linux-user/m68k-sim.c
@@ -98,6 +98,7 @@
 #define ARG(x) tswap32(args[x])
 void do_m68k_simcall(CPUM68KState *env, int nr)
 {
+    M68kCPU *cpu = m68k_env_get_cpu(env);
     uint32_t *args;
 
     args = (uint32_t *)(unsigned long)(env->aregs[7] + 4);
@@ -165,6 +166,6 @@
         check_err(env, lseek(ARG(0), (int32_t)ARG(1), ARG(2)));
         break;
     default:
-        cpu_abort(env, "Unsupported m68k sim syscall %d\n", nr);
+        cpu_abort(CPU(cpu), "Unsupported m68k sim syscall %d\n", nr);
     }
 }
diff --git a/linux-user/m68k/target_cpu.h b/linux-user/m68k/target_cpu.h
index cad9c90..bb4d3fa 100644
--- a/linux-user/m68k/target_cpu.h
+++ b/linux-user/m68k/target_cpu.h
@@ -31,7 +31,9 @@
 
 static inline void cpu_set_tls(CPUM68KState *env, target_ulong newtls)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(m68k_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
+
     ts->tp_value = newtls;
 }
 
diff --git a/linux-user/main.c b/linux-user/main.c
index dee1084..af924dc 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -685,7 +685,7 @@
         switch(trapnr) {
         case EXCP_UDEF:
             {
-                TaskState *ts = env->opaque;
+                TaskState *ts = cs->opaque;
                 uint32_t opcode;
                 int rc;
 
@@ -1577,11 +1577,11 @@
             /* Just go on */
             break;
         case POWERPC_EXCP_CRITICAL: /* Critical input                        */
-            cpu_abort(env, "Critical interrupt while in user mode. "
+            cpu_abort(cs, "Critical interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
-            cpu_abort(env, "Machine check exception while in user mode. "
+            cpu_abort(cs, "Machine check exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_DSI:      /* Data storage exception                */
@@ -1645,7 +1645,7 @@
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_EXTERNAL: /* External input                        */
-            cpu_abort(env, "External interrupt while in user mode. "
+            cpu_abort(cs, "External interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
@@ -1739,11 +1739,11 @@
                 }
                 break;
             case POWERPC_EXCP_TRAP:
-                cpu_abort(env, "Tried to call a TRAP\n");
+                cpu_abort(cs, "Tried to call a TRAP\n");
                 break;
             default:
                 /* Should not happen ! */
-                cpu_abort(env, "Unknown program exception (%02x)\n",
+                cpu_abort(cs, "Unknown program exception (%02x)\n",
                           env->error_code);
                 break;
             }
@@ -1759,7 +1759,7 @@
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
-            cpu_abort(env, "Syscall exception while in user mode. "
+            cpu_abort(cs, "Syscall exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
@@ -1771,23 +1771,23 @@
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
-            cpu_abort(env, "Decrementer interrupt while in user mode. "
+            cpu_abort(cs, "Decrementer interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
-            cpu_abort(env, "Fix interval timer interrupt while in user mode. "
+            cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
-            cpu_abort(env, "Watchdog timer interrupt while in user mode. "
+            cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
-            cpu_abort(env, "Data TLB exception while in user mode. "
+            cpu_abort(cs, "Data TLB exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
-            cpu_abort(env, "Instruction TLB exception while in user mode. "
+            cpu_abort(cs, "Instruction TLB exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
@@ -1799,37 +1799,37 @@
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
-            cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
+            cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
             break;
         case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
-            cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
+            cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
             break;
         case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
-            cpu_abort(env, "Performance monitor exception not handled\n");
+            cpu_abort(cs, "Performance monitor exception not handled\n");
             break;
         case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
-            cpu_abort(env, "Doorbell interrupt while in user mode. "
+            cpu_abort(cs, "Doorbell interrupt while in user mode. "
                        "Aborting\n");
             break;
         case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
-            cpu_abort(env, "Doorbell critical interrupt while in user mode. "
+            cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_RESET:    /* System reset exception                */
-            cpu_abort(env, "Reset interrupt while in user mode. "
+            cpu_abort(cs, "Reset interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_DSEG:     /* Data segment exception                */
-            cpu_abort(env, "Data segment exception while in user mode. "
+            cpu_abort(cs, "Data segment exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
-            cpu_abort(env, "Instruction segment exception "
+            cpu_abort(cs, "Instruction segment exception "
                       "while in user mode. Aborting\n");
             break;
         /* PowerPC 64 with hypervisor mode support */
         case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
-            cpu_abort(env, "Hypervisor decrementer interrupt "
+            cpu_abort(cs, "Hypervisor decrementer interrupt "
                       "while in user mode. Aborting\n");
             break;
         case POWERPC_EXCP_TRACE:    /* Trace exception                       */
@@ -1839,19 +1839,19 @@
             break;
         /* PowerPC 64 with hypervisor mode support */
         case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
-            cpu_abort(env, "Hypervisor data storage exception "
+            cpu_abort(cs, "Hypervisor data storage exception "
                       "while in user mode. Aborting\n");
             break;
         case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
-            cpu_abort(env, "Hypervisor instruction storage exception "
+            cpu_abort(cs, "Hypervisor instruction storage exception "
                       "while in user mode. Aborting\n");
             break;
         case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
-            cpu_abort(env, "Hypervisor data segment exception "
+            cpu_abort(cs, "Hypervisor data segment exception "
                       "while in user mode. Aborting\n");
             break;
         case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
-            cpu_abort(env, "Hypervisor instruction segment exception "
+            cpu_abort(cs, "Hypervisor instruction segment exception "
                       "while in user mode. Aborting\n");
             break;
         case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
@@ -1863,58 +1863,58 @@
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
-            cpu_abort(env, "Programmable interval timer interrupt "
+            cpu_abort(cs, "Programmable interval timer interrupt "
                       "while in user mode. Aborting\n");
             break;
         case POWERPC_EXCP_IO:       /* IO error exception                    */
-            cpu_abort(env, "IO error exception while in user mode. "
+            cpu_abort(cs, "IO error exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
-            cpu_abort(env, "Run mode exception while in user mode. "
+            cpu_abort(cs, "Run mode exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
-            cpu_abort(env, "Emulation trap exception not handled\n");
+            cpu_abort(cs, "Emulation trap exception not handled\n");
             break;
         case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
-            cpu_abort(env, "Instruction fetch TLB exception "
+            cpu_abort(cs, "Instruction fetch TLB exception "
                       "while in user-mode. Aborting");
             break;
         case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
-            cpu_abort(env, "Data load TLB exception while in user-mode. "
+            cpu_abort(cs, "Data load TLB exception while in user-mode. "
                       "Aborting");
             break;
         case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
-            cpu_abort(env, "Data store TLB exception while in user-mode. "
+            cpu_abort(cs, "Data store TLB exception while in user-mode. "
                       "Aborting");
             break;
         case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
-            cpu_abort(env, "Floating-point assist exception not handled\n");
+            cpu_abort(cs, "Floating-point assist exception not handled\n");
             break;
         case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
-            cpu_abort(env, "Instruction address breakpoint exception "
+            cpu_abort(cs, "Instruction address breakpoint exception "
                       "not handled\n");
             break;
         case POWERPC_EXCP_SMI:      /* System management interrupt           */
-            cpu_abort(env, "System management interrupt while in user mode. "
+            cpu_abort(cs, "System management interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
-            cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
+            cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
-            cpu_abort(env, "Performance monitor exception not handled\n");
+            cpu_abort(cs, "Performance monitor exception not handled\n");
             break;
         case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
-            cpu_abort(env, "Vector assist exception not handled\n");
+            cpu_abort(cs, "Vector assist exception not handled\n");
             break;
         case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
-            cpu_abort(env, "Soft patch exception not handled\n");
+            cpu_abort(cs, "Soft patch exception not handled\n");
             break;
         case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
-            cpu_abort(env, "Maintenance exception while in user mode. "
+            cpu_abort(cs, "Maintenance exception while in user mode. "
                       "Aborting\n");
             break;
         case POWERPC_EXCP_STOP:     /* stop translation                      */
@@ -1970,7 +1970,7 @@
             /* just indicate that signals should be handled asap */
             break;
         default:
-            cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
+            cpu_abort(cs, "Unknown exception 0x%d. Aborting\n", trapnr);
             break;
         }
         process_pending_signals(env);
@@ -2965,7 +2965,7 @@
     int trapnr;
     unsigned int n;
     target_siginfo_t info;
-    TaskState *ts = env->opaque;
+    TaskState *ts = cs->opaque;
 
     for(;;) {
         trapnr = cpu_m68k_exec(env);
@@ -3435,28 +3435,30 @@
 
 CPUArchState *cpu_copy(CPUArchState *env)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
     CPUArchState *new_env = cpu_init(cpu_model);
+    CPUState *new_cpu = ENV_GET_CPU(new_env);
 #if defined(TARGET_HAS_ICE)
     CPUBreakpoint *bp;
     CPUWatchpoint *wp;
 #endif
 
     /* Reset non arch specific state */
-    cpu_reset(ENV_GET_CPU(new_env));
+    cpu_reset(new_cpu);
 
     memcpy(new_env, env, sizeof(CPUArchState));
 
     /* Clone all break/watchpoints.
        Note: Once we support ptrace with hw-debug register access, make sure
        BP_CPU break/watchpoints are handled correctly on clone. */
-    QTAILQ_INIT(&env->breakpoints);
-    QTAILQ_INIT(&env->watchpoints);
+    QTAILQ_INIT(&cpu->breakpoints);
+    QTAILQ_INIT(&cpu->watchpoints);
 #if defined(TARGET_HAS_ICE)
-    QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
-        cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
+    QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
+        cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
     }
-    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
-        cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
+    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
+        cpu_watchpoint_insert(new_cpu, wp->vaddr, (~wp->len_mask) + 1,
                               wp->flags, NULL);
     }
 #endif
@@ -4001,7 +4003,7 @@
     /* build Task State */
     ts->info = info;
     ts->bprm = &bprm;
-    env->opaque = ts;
+    cpu->opaque = ts;
     task_settid(ts);
 
     execfd = qemu_getauxval(AT_EXECFD);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index c8a1da0..24c91f3 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -370,7 +370,8 @@
 
 static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cpu = ENV_GET_CPU(env);
+    TaskState *ts = cpu->opaque;
     struct sigqueue *q = ts->first_free;
     if (!q)
         return NULL;
@@ -380,7 +381,9 @@
 
 static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cpu = ENV_GET_CPU(env);
+    TaskState *ts = cpu->opaque;
+
     q->next = ts->first_free;
     ts->first_free = q;
 }
@@ -388,8 +391,9 @@
 /* abort execution with signal */
 static void QEMU_NORETURN force_sig(int target_sig)
 {
-    CPUArchState *env = thread_cpu->env_ptr;
-    TaskState *ts = (TaskState *)env->opaque;
+    CPUState *cpu = thread_cpu;
+    CPUArchState *env = cpu->env_ptr;
+    TaskState *ts = (TaskState *)cpu->opaque;
     int host_sig, core_dumped = 0;
     struct sigaction act;
     host_sig = target_to_host_signal(target_sig);
@@ -440,7 +444,8 @@
    as possible */
 int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cpu = ENV_GET_CPU(env);
+    TaskState *ts = cpu->opaque;
     struct emulated_sigtable *k;
     struct sigqueue *q, **pq;
     abi_ulong handler;
@@ -774,8 +779,9 @@
 setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
 		 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
 {
-	int err = 0;
-        uint16_t magic;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    int err = 0;
+    uint16_t magic;
 
 	/* already locked in setup_frame() */
 	err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
@@ -790,7 +796,7 @@
 	err |= __put_user(env->regs[R_EDX], &sc->edx);
 	err |= __put_user(env->regs[R_ECX], &sc->ecx);
 	err |= __put_user(env->regs[R_EAX], &sc->eax);
-	err |= __put_user(env->exception_index, &sc->trapno);
+    err |= __put_user(cs->exception_index, &sc->trapno);
 	err |= __put_user(env->error_code, &sc->err);
 	err |= __put_user(env->eip, &sc->eip);
 	err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
@@ -5675,7 +5681,7 @@
     struct emulated_sigtable *k;
     struct target_sigaction *sa;
     struct sigqueue *q;
-    TaskState *ts = cpu_env->opaque;
+    TaskState *ts = cpu->opaque;
 
     if (!ts->signal_pending)
         return;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e2c10cc..ffc11de 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4243,7 +4243,7 @@
     env = info->env;
     cpu = ENV_GET_CPU(env);
     thread_cpu = cpu;
-    ts = (TaskState *)env->opaque;
+    ts = (TaskState *)cpu->opaque;
     info->tid = gettid();
     cpu->host_tid = info->tid;
     task_settid(ts);
@@ -4271,8 +4271,10 @@
                    abi_ulong parent_tidptr, target_ulong newtls,
                    abi_ulong child_tidptr)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
     int ret;
     TaskState *ts;
+    CPUState *new_cpu;
     CPUArchState *new_env;
     unsigned int nptl_flags;
     sigset_t sigmask;
@@ -4282,7 +4284,7 @@
         flags &= ~(CLONE_VFORK | CLONE_VM);
 
     if (flags & CLONE_VM) {
-        TaskState *parent_ts = (TaskState *)env->opaque;
+        TaskState *parent_ts = (TaskState *)cpu->opaque;
         new_thread_info info;
         pthread_attr_t attr;
 
@@ -4292,7 +4294,8 @@
         new_env = cpu_copy(env);
         /* Init regs that differ from the parent.  */
         cpu_clone_regs(new_env, newsp);
-        new_env->opaque = ts;
+        new_cpu = ENV_GET_CPU(new_env);
+        new_cpu->opaque = ts;
         ts->bprm = parent_ts->bprm;
         ts->info = parent_ts->info;
         nptl_flags = flags;
@@ -4364,7 +4367,7 @@
                 put_user_u32(gettid(), child_tidptr);
             if (flags & CLONE_PARENT_SETTID)
                 put_user_u32(gettid(), parent_tidptr);
-            ts = (TaskState *)env->opaque;
+            ts = (TaskState *)cpu->opaque;
             if (flags & CLONE_SETTLS)
                 cpu_set_tls (env, newtls);
             if (flags & CLONE_CHILD_CLEARTID)
@@ -4974,7 +4977,8 @@
 static int open_self_maps(void *cpu_env, int fd)
 {
 #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
-    TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+    TaskState *ts = cpu->opaque;
 #endif
     FILE *fp;
     char *line = NULL;
@@ -5026,7 +5030,8 @@
 
 static int open_self_stat(void *cpu_env, int fd)
 {
-    TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+    TaskState *ts = cpu->opaque;
     abi_ulong start_stack = ts->info->start_stack;
     int i;
 
@@ -5062,7 +5067,8 @@
 
 static int open_self_auxv(void *cpu_env, int fd)
 {
-    TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+    TaskState *ts = cpu->opaque;
     abi_ulong auxv = ts->info->saved_auxv;
     abi_ulong len = ts->info->auxv_len;
     char *ptr;
@@ -5244,14 +5250,14 @@
             /* Remove the CPU from the list.  */
             QTAILQ_REMOVE(&cpus, cpu, node);
             cpu_list_unlock();
-            ts = ((CPUArchState *)cpu_env)->opaque;
+            ts = cpu->opaque;
             if (ts->child_tidptr) {
                 put_user_u32(0, ts->child_tidptr);
                 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
                           NULL, NULL, 0);
             }
             thread_cpu = NULL;
-            object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
+            object_unref(OBJECT(cpu));
             g_free(ts);
             pthread_exit(NULL);
         }
@@ -6555,7 +6561,7 @@
         break;
     case TARGET_NR_mprotect:
         {
-            TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+            TaskState *ts = cpu->opaque;
             /* Special hack to detect libc making the stack executable.  */
             if ((arg3 & PROT_GROWSDOWN)
                 && arg1 >= ts->info->stack_limit
@@ -8647,7 +8653,7 @@
       break;
 #elif defined(TARGET_M68K)
       {
-          TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+          TaskState *ts = cpu->opaque;
           ts->tp_value = arg1;
           ret = 0;
           break;
@@ -8663,7 +8669,7 @@
         break;
 #elif defined(TARGET_M68K)
         {
-            TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+            TaskState *ts = cpu->opaque;
             ret = ts->tp_value;
             break;
         }
diff --git a/linux-user/vm86.c b/linux-user/vm86.c
index 2c4ffeb..45ef559 100644
--- a/linux-user/vm86.c
+++ b/linux-user/vm86.c
@@ -72,7 +72,8 @@
 
 void save_v86_state(CPUX86State *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
     struct target_vm86plus_struct * target_v86;
 
     if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
@@ -131,7 +132,8 @@
 
 static inline int set_IF(CPUX86State *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
 
     ts->v86flags |= VIF_MASK;
     if (ts->v86flags & VIP_MASK) {
@@ -143,7 +145,8 @@
 
 static inline void clear_IF(CPUX86State *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
 
     ts->v86flags &= ~VIF_MASK;
 }
@@ -160,7 +163,8 @@
 
 static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
 
     set_flags(ts->v86flags, eflags, ts->v86mask);
     set_flags(env->eflags, eflags, SAFE_MASK);
@@ -173,7 +177,8 @@
 
 static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
 
     set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
     set_flags(env->eflags, flags, SAFE_MASK);
@@ -186,7 +191,8 @@
 
 static inline unsigned int get_vflags(CPUX86State *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
     unsigned int flags;
 
     flags = env->eflags & RETURN_MASK;
@@ -202,7 +208,8 @@
    support TSS interrupt revectoring, so this code is always executed) */
 static void do_int(CPUX86State *env, int intno)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
     uint32_t int_addr, segoffs, ssp;
     unsigned int sp;
 
@@ -260,7 +267,8 @@
 
 void handle_vm86_fault(CPUX86State *env)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
     uint32_t csp, ssp;
     unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
     int data32, pref_done;
@@ -384,7 +392,8 @@
 
 int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
 {
-    TaskState *ts = env->opaque;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+    TaskState *ts = cs->opaque;
     struct target_vm86plus_struct * target_v86;
     int ret;
 
diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin
index d378d9a..e7f7693 100644
--- a/pc-bios/ppc_rom.bin
+++ b/pc-bios/ppc_rom.bin
Binary files differ
diff --git a/qom/cpu.c b/qom/cpu.c
index 9d62479..fada2d4 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -1,7 +1,7 @@
 /*
  * QEMU CPU model
  *
- * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * Copyright (c) 2012-2014 SUSE LINUX Products GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -23,6 +23,7 @@
 #include "sysemu/kvm.h"
 #include "qemu/notify.h"
 #include "qemu/log.h"
+#include "qemu/error-report.h"
 #include "sysemu/sysemu.h"
 
 bool cpu_exists(int64_t id)
@@ -39,6 +40,46 @@
     return false;
 }
 
+CPUState *cpu_generic_init(const char *typename, const char *cpu_model)
+{
+    char *str, *name, *featurestr;
+    CPUState *cpu;
+    ObjectClass *oc;
+    CPUClass *cc;
+    Error *err = NULL;
+
+    str = g_strdup(cpu_model);
+    name = strtok(str, ",");
+
+    oc = cpu_class_by_name(typename, name);
+    if (oc == NULL) {
+        g_free(str);
+        return NULL;
+    }
+
+    cpu = CPU(object_new(object_class_get_name(oc)));
+    cc = CPU_GET_CLASS(cpu);
+
+    featurestr = strtok(NULL, ",");
+    cc->parse_features(cpu, featurestr, &err);
+    g_free(str);
+    if (err != NULL) {
+        goto out;
+    }
+
+    object_property_set_bool(OBJECT(cpu), true, "realized", &err);
+
+out:
+    if (err != NULL) {
+        error_report("%s", error_get_pretty(err));
+        error_free(err);
+        object_unref(OBJECT(cpu));
+        return NULL;
+    }
+
+    return cpu;
+}
+
 bool cpu_paging_enabled(const CPUState *cpu)
 {
     CPUClass *cc = CPU_GET_CLASS(cpu);
@@ -195,10 +236,20 @@
         log_cpu_state(cpu, cc->reset_dump_flags);
     }
 
-    cpu->exit_request = 0;
     cpu->interrupt_request = 0;
     cpu->current_tb = NULL;
     cpu->halted = 0;
+    cpu->mem_io_pc = 0;
+    cpu->mem_io_vaddr = 0;
+    cpu->icount_extra = 0;
+    cpu->icount_decr.u32 = 0;
+    cpu->can_do_io = 0;
+    memset(cpu->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *));
+}
+
+static bool cpu_common_has_work(CPUState *cs)
+{
+    return false;
 }
 
 ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
@@ -213,6 +264,34 @@
     return NULL;
 }
 
+static void cpu_common_parse_features(CPUState *cpu, char *features,
+                                      Error **errp)
+{
+    char *featurestr; /* Single "key=value" string being parsed */
+    char *val;
+    Error *err = NULL;
+
+    featurestr = features ? strtok(features, ",") : NULL;
+
+    while (featurestr) {
+        val = strchr(featurestr, '=');
+        if (val) {
+            *val = 0;
+            val++;
+            object_property_parse(OBJECT(cpu), val, featurestr, &err);
+            if (err) {
+                error_propagate(errp, err);
+                return;
+            }
+        } else {
+            error_setg(errp, "Expected key=value format, found %s.",
+                       featurestr);
+            return;
+        }
+        featurestr = strtok(NULL, ",");
+    }
+}
+
 static void cpu_common_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cpu = CPU(dev);
@@ -243,8 +322,10 @@
     CPUClass *k = CPU_CLASS(klass);
 
     k->class_by_name = cpu_common_class_by_name;
+    k->parse_features = cpu_common_parse_features;
     k->reset = cpu_common_reset;
     k->get_arch_id = cpu_common_get_arch_id;
+    k->has_work = cpu_common_has_work;
     k->get_paging_enabled = cpu_common_get_paging_enabled;
     k->get_memory_mapping = cpu_common_get_memory_mapping;
     k->write_elf32_qemunote = cpu_common_write_elf32_qemunote;
diff --git a/roms/openhackware b/roms/openhackware
index e9829b5..1af7e55 160000
--- a/roms/openhackware
+++ b/roms/openhackware
@@ -1 +1 @@
-Subproject commit e9829b5584169ad14df2ca8776b87f4985aa9f06
+Subproject commit 1af7e55425e58a6dcb5133b092fcf16f8c654fb9
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index a0d5d5b..7ec46b9 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -31,6 +31,21 @@
     cpu->env.pc = value;
 }
 
+static bool alpha_cpu_has_work(CPUState *cs)
+{
+    /* 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
+       asleep even if (some) interrupts have been asserted.  For now,
+       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 cs->interrupt_request & (CPU_INTERRUPT_HARD
+                                    | CPU_INTERRUPT_TIMER
+                                    | CPU_INTERRUPT_SMP
+                                    | CPU_INTERRUPT_MCHK);
+}
+
 static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
@@ -243,7 +258,7 @@
 
     cs->env_ptr = env;
     cpu_exec_init(env);
-    tlb_flush(env, 1);
+    tlb_flush(cs, 1);
 
     alpha_translate_init();
 
@@ -267,12 +282,15 @@
     dc->realize = alpha_cpu_realizefn;
 
     cc->class_by_name = alpha_cpu_class_by_name;
+    cc->has_work = alpha_cpu_has_work;
     cc->do_interrupt = alpha_cpu_do_interrupt;
     cc->dump_state = alpha_cpu_dump_state;
     cc->set_pc = alpha_cpu_set_pc;
     cc->gdb_read_register = alpha_cpu_gdb_read_register;
     cc->gdb_write_register = alpha_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = alpha_cpu_handle_mmu_fault;
+#else
     cc->do_unassigned_access = alpha_cpu_unassigned_access;
     cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
     dc->vmsd = &vmstate_alpha_cpu;
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c85dc6e..07d9f63 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -446,9 +446,8 @@
    is returned if the signal was handled by the virtual CPU.  */
 int cpu_alpha_signal_handler(int host_signum, void *pinfo,
                              void *puc);
-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
+int alpha_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                               int mmu_idx);
 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);
@@ -498,21 +497,6 @@
     *pflags = flags;
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    /* 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
-       asleep even if (some) interrupts have been asserted.  For now,
-       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 cpu->interrupt_request & (CPU_INTERRUPT_HARD
-                                     | CPU_INTERRUPT_TIMER
-                                     | CPU_INTERRUPT_SMP
-                                     | CPU_INTERRUPT_MCHK);
-}
-
 #include "exec/exec-all.h"
 
 #endif /* !defined (__CPU_ALPHA_H__) */
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 025fdaf..cbd03c4 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -168,11 +168,13 @@
 }
 
 #if defined(CONFIG_USER_ONLY)
-int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong address,
+int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
                                int rw, int mmu_idx)
 {
-    env->exception_index = EXCP_MMFAULT;
-    env->trap_arg0 = address;
+    AlphaCPU *cpu = ALPHA_CPU(cs);
+
+    cs->exception_index = EXCP_MMFAULT;
+    cpu->env.trap_arg0 = address;
     return 1;
 }
 #else
@@ -213,7 +215,7 @@
                                 int prot_need, int mmu_idx,
                                 target_ulong *pphys, int *pprot)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     target_long saddr = addr;
     target_ulong phys = 0;
     target_ulong L1pte, L2pte, L3pte;
@@ -326,22 +328,24 @@
     return (fail >= 0 ? -1 : phys);
 }
 
-int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong addr, int rw,
+int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, int rw,
                                int mmu_idx)
 {
+    AlphaCPU *cpu = ALPHA_CPU(cs);
+    CPUAlphaState *env = &cpu->env;
     target_ulong phys;
     int prot, fail;
 
     fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
     if (unlikely(fail >= 0)) {
-        env->exception_index = EXCP_MMFAULT;
+        cs->exception_index = EXCP_MMFAULT;
         env->trap_arg0 = addr;
         env->trap_arg1 = fail;
         env->trap_arg2 = (rw == 2 ? -1 : rw);
         return 1;
     }
 
-    tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
+    tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
                  prot, mmu_idx, TARGET_PAGE_SIZE);
     return 0;
 }
@@ -351,7 +355,7 @@
 {
     AlphaCPU *cpu = ALPHA_CPU(cs);
     CPUAlphaState *env = &cpu->env;
-    int i = env->exception_index;
+    int i = cs->exception_index;
 
     if (qemu_loglevel_mask(CPU_LOG_INT)) {
         static int count;
@@ -402,7 +406,7 @@
                  ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
     }
 
-    env->exception_index = -1;
+    cs->exception_index = -1;
 
 #if !defined(CONFIG_USER_ONLY)
     switch (i) {
@@ -448,7 +452,7 @@
         }
         break;
     default:
-        cpu_abort(env, "Unhandled CPU exception");
+        cpu_abort(cs, "Unhandled CPU exception");
     }
 
     /* Remember where the exception happened.  Emulate real hardware in
@@ -504,21 +508,27 @@
    We expect that ENV->PC has already been updated.  */
 void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
 {
-    env->exception_index = excp;
+    AlphaCPU *cpu = alpha_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
+    cs->exception_index = excp;
     env->error_code = error;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 /* This may be called from any of the helpers to set up EXCEPTION_INDEX.  */
 void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
                                 int excp, int error)
 {
-    env->exception_index = excp;
+    AlphaCPU *cpu = alpha_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
+    cs->exception_index = excp;
     env->error_code = error;
     if (retaddr) {
-        cpu_restore_state(env, retaddr);
+        cpu_restore_state(cs, retaddr);
     }
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
diff --git a/target-alpha/mem_helper.c b/target-alpha/mem_helper.c
index ea58704..5964bdc 100644
--- a/target-alpha/mem_helper.c
+++ b/target-alpha/mem_helper.c
@@ -26,45 +26,45 @@
 
 uint64_t helper_ldl_phys(CPUAlphaState *env, uint64_t p)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     return (int32_t)ldl_phys(cs->as, p);
 }
 
 uint64_t helper_ldq_phys(CPUAlphaState *env, uint64_t p)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     return ldq_phys(cs->as, p);
 }
 
 uint64_t helper_ldl_l_phys(CPUAlphaState *env, uint64_t p)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     env->lock_addr = p;
     return env->lock_value = (int32_t)ldl_phys(cs->as, p);
 }
 
 uint64_t helper_ldq_l_phys(CPUAlphaState *env, uint64_t p)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     env->lock_addr = p;
     return env->lock_value = ldq_phys(cs->as, p);
 }
 
 void helper_stl_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     stl_phys(cs->as, p, v);
 }
 
 void helper_stq_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     stq_phys(cs->as, p, v);
 }
 
 uint64_t helper_stl_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     uint64_t ret = 0;
 
     if (p == env->lock_addr) {
@@ -81,7 +81,7 @@
 
 uint64_t helper_stq_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(alpha_env_get_cpu(env));
     uint64_t ret = 0;
 
     if (p == env->lock_addr) {
@@ -99,11 +99,13 @@
 static void do_unaligned_access(CPUAlphaState *env, target_ulong addr,
                                 int is_write, int is_user, uintptr_t retaddr)
 {
+    AlphaCPU *cpu = alpha_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
     uint64_t pc;
     uint32_t insn;
 
     if (retaddr) {
-        cpu_restore_state(env, retaddr);
+        cpu_restore_state(cs, retaddr);
     }
 
     pc = env->pc;
@@ -112,9 +114,9 @@
     env->trap_arg0 = addr;
     env->trap_arg1 = insn >> 26;                /* opcode */
     env->trap_arg2 = (insn >> 21) & 31;         /* dest regno */
-    env->exception_index = EXCP_UNALIGN;
+    cs->exception_index = EXCP_UNALIGN;
     env->error_code = 0;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void alpha_cpu_unassigned_access(CPUState *cs, hwaddr addr,
@@ -150,18 +152,18 @@
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(CPUAlphaState *env, target_ulong addr, int is_write,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write,
               int mmu_idx, uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = alpha_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (retaddr) {
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
         /* Exception index and error code are already set */
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 #endif /* CONFIG_USER_ONLY */
diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c
index 035810c..187ccf7 100644
--- a/target-alpha/sys_helper.c
+++ b/target-alpha/sys_helper.c
@@ -64,12 +64,12 @@
 
 void helper_tbia(CPUAlphaState *env)
 {
-    tlb_flush(env, 1);
+    tlb_flush(CPU(alpha_env_get_cpu(env)), 1);
 }
 
 void helper_tbis(CPUAlphaState *env, uint64_t p)
 {
-    tlb_flush_page(env, p);
+    tlb_flush_page(CPU(alpha_env_get_cpu(env)), p);
 }
 
 void helper_tb_flush(CPUAlphaState *env)
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 4c94bed..a9ef1a7 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -3463,8 +3463,8 @@
 
     gen_tb_start();
     do {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == ctx.pc) {
                     gen_excp(&ctx, EXCP_DEBUG, 0);
                     break;
diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c
index ee469c4..ebb5235 100644
--- a/target-arm/arm-semi.c
+++ b/target-arm/arm-semi.c
@@ -127,7 +127,7 @@
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
 #ifdef CONFIG_USER_ONLY
-    TaskState *ts = env->opaque;
+    TaskState *ts = cs->opaque;
 #endif
 
     if (ret == (target_ulong)-1) {
@@ -164,7 +164,7 @@
     cpu_memory_rw_debug(cs, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
     env->regs[0] = be32_to_cpu(size);
 #ifdef CONFIG_USER_ONLY
-    ((TaskState *)env->opaque)->swi_errno = err;
+    ((TaskState *)cs->opaque)->swi_errno = err;
 #else
     syscall_err = err;
 #endif
@@ -183,6 +183,7 @@
 uint32_t do_arm_semihosting(CPUARMState *env)
 {
     ARMCPU *cpu = arm_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
     target_ulong args;
     target_ulong arg0, arg1, arg2, arg3;
     char * s;
@@ -190,7 +191,7 @@
     uint32_t ret;
     uint32_t len;
 #ifdef CONFIG_USER_ONLY
-    TaskState *ts = env->opaque;
+    TaskState *ts = cs->opaque;
 #else
     CPUARMState *ts = env;
 #endif
@@ -554,7 +555,7 @@
         exit(0);
     default:
         fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
-        cpu_dump_state(CPU(cpu), stderr, fprintf, 0);
+        cpu_dump_state(cs, stderr, fprintf, 0);
         abort();
     }
 }
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 1ce8a9b..c32d8c4 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -36,6 +36,12 @@
     cpu->env.regs[15] = value;
 }
 
+static bool arm_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request &
+        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
 static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
 {
     /* Reset a single ARMCPRegInfo register */
@@ -76,7 +82,7 @@
 
     acc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUARMState, breakpoints));
+    memset(env, 0, offsetof(CPUARMState, features));
     g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
     env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
     env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
@@ -143,7 +149,7 @@
                               &env->vfp.fp_status);
     set_float_detect_tininess(float_tininess_before_rounding,
                               &env->vfp.standard_fp_status);
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
     /* Reset is a state change for some CPUARMState fields which we
      * bake assumptions about into translated code, so we need to
      * tb_flush().
@@ -1001,12 +1007,15 @@
     cc->reset = arm_cpu_reset;
 
     cc->class_by_name = arm_cpu_class_by_name;
+    cc->has_work = arm_cpu_has_work;
     cc->do_interrupt = arm_cpu_do_interrupt;
     cc->dump_state = arm_cpu_dump_state;
     cc->set_pc = arm_cpu_set_pc;
     cc->gdb_read_register = arm_cpu_gdb_read_register;
     cc->gdb_write_register = arm_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = arm_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
     cc->vmsd = &vmstate_arm_cpu;
 #endif
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 0a7edfe..bf37cd6 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -339,9 +339,8 @@
    is returned if the signal was handled by the virtual CPU.  */
 int cpu_arm_signal_handler(int host_signum, void *pinfo,
                            void *puc);
-int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
-                              int mmu_idx);
-#define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault
+int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                             int mmu_idx);
 
 /* SCTLR bit meanings. Several bits have been reused in newer
  * versions of the architecture; in that case we define constants
@@ -1166,12 +1165,6 @@
     *cs_base = 0;
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request &
-        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
-}
-
 #include "exec/exec-all.h"
 
 static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index f65cbac..aa5f22d 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -303,17 +303,21 @@
 
 static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     env->cp15.c3 = value;
-    tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */
+    tlb_flush(CPU(cpu), 1); /* Flush TLB as domain not tracked in TLB */
 }
 
 static void fcse_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     if (env->cp15.c13_fcse != value) {
         /* Unlike real hardware the qemu TLB uses virtual addresses,
          * not modified virtual addresses, so this causes a TLB flush.
          */
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
         env->cp15.c13_fcse = value;
     }
 }
@@ -321,12 +325,14 @@
 static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                              uint64_t value)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     if (env->cp15.c13_context != value && !arm_feature(env, ARM_FEATURE_MPU)) {
         /* For VMSA (when not using the LPAE long descriptor page table
          * format) this register includes the ASID, so do a TLB flush.
          * For PMSA it is purely a process ID and no action is needed.
          */
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
     env->cp15.c13_context = value;
 }
@@ -335,28 +341,36 @@
                           uint64_t value)
 {
     /* Invalidate all (TLBIALL) */
-    tlb_flush(env, 1);
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    tlb_flush(CPU(cpu), 1);
 }
 
 static void tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
                           uint64_t value)
 {
     /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
-    tlb_flush_page(env, value & TARGET_PAGE_MASK);
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    tlb_flush_page(CPU(cpu), value & TARGET_PAGE_MASK);
 }
 
 static void tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
                            uint64_t value)
 {
     /* Invalidate by ASID (TLBIASID) */
-    tlb_flush(env, value == 0);
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    tlb_flush(CPU(cpu), value == 0);
 }
 
 static void tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
                            uint64_t value)
 {
     /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
-    tlb_flush_page(env, value & TARGET_PAGE_MASK);
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    tlb_flush_page(CPU(cpu), value & TARGET_PAGE_MASK);
 }
 
 static const ARMCPRegInfo cp_reginfo[] = {
@@ -1348,11 +1362,13 @@
 static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                              uint64_t value)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     if (arm_feature(env, ARM_FEATURE_LPAE)) {
         /* With LPAE the TTBCR could result in a change of ASID
          * via the TTBCR.A1 bit, so do a TLB flush.
          */
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
     vmsa_ttbcr_raw_write(env, ri, value);
 }
@@ -1367,8 +1383,10 @@
 static void vmsa_tcr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                uint64_t value)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     /* For AArch64 the A1 bit could result in a change of ASID, so TLB flush. */
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
     env->cp15.c2_control = value;
 }
 
@@ -1379,7 +1397,9 @@
      * must flush the TLB.
      */
     if (cpreg_field_is_64bit(ri)) {
-        tlb_flush(env, 1);
+        ARMCPU *cpu = arm_env_get_cpu(env);
+
+        tlb_flush(CPU(cpu), 1);
     }
     raw_write(env, ri, value);
 }
@@ -1686,24 +1706,27 @@
                                uint64_t value)
 {
     /* Invalidate by VA (AArch64 version) */
+    ARMCPU *cpu = arm_env_get_cpu(env);
     uint64_t pageaddr = value << 12;
-    tlb_flush_page(env, pageaddr);
+    tlb_flush_page(CPU(cpu), pageaddr);
 }
 
 static void tlbi_aa64_vaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                 uint64_t value)
 {
     /* Invalidate by VA, all ASIDs (AArch64 version) */
+    ARMCPU *cpu = arm_env_get_cpu(env);
     uint64_t pageaddr = value << 12;
-    tlb_flush_page(env, pageaddr);
+    tlb_flush_page(CPU(cpu), pageaddr);
 }
 
 static void tlbi_aa64_asid_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                  uint64_t value)
 {
     /* Invalidate by ASID (AArch64 version) */
+    ARMCPU *cpu = arm_env_get_cpu(env);
     int asid = extract64(value, 48, 16);
-    tlb_flush(env, asid == 0);
+    tlb_flush(CPU(cpu), asid == 0);
 }
 
 static const ARMCPRegInfo v8_cp_reginfo[] = {
@@ -1829,10 +1852,12 @@
 static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                         uint64_t value)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     env->cp15.c1_sys = value;
     /* ??? Lots of these bits are not implemented.  */
     /* This may enable/disable the MMU, so do a TLB flush.  */
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -2186,19 +2211,7 @@
 
 ARMCPU *cpu_arm_init(const char *cpu_model)
 {
-    ARMCPU *cpu;
-    ObjectClass *oc;
-
-    oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
-    if (!oc) {
-        return NULL;
-    }
-    cpu = ARM_CPU(object_new(object_class_get_name(oc)));
-
-    /* TODO this should be set centrally, once possible */
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return cpu;
+    return ARM_CPU(cpu_generic_init(TYPE_ARM_CPU, cpu_model));
 }
 
 void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
@@ -2661,20 +2674,20 @@
 
 void arm_cpu_do_interrupt(CPUState *cs)
 {
+    cs->exception_index = -1;
+}
+
+int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                             int mmu_idx)
+{
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
 
-    env->exception_index = -1;
-}
-
-int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
-                              int mmu_idx)
-{
     if (rw == 2) {
-        env->exception_index = EXCP_PREFETCH_ABORT;
+        cs->exception_index = EXCP_PREFETCH_ABORT;
         env->cp15.c6_insn = address;
     } else {
-        env->exception_index = EXCP_DATA_ABORT;
+        cs->exception_index = EXCP_DATA_ABORT;
         env->cp15.c6_data = address;
     }
     return 1;
@@ -2683,29 +2696,40 @@
 /* These should probably raise undefined insn exceptions.  */
 void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
 {
-    cpu_abort(env, "v7m_mrs %d\n", reg);
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
 }
 
 uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
 {
-    cpu_abort(env, "v7m_mrs %d\n", reg);
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
     return 0;
 }
 
 void switch_mode(CPUARMState *env, int mode)
 {
-    if (mode != ARM_CPU_MODE_USR)
-        cpu_abort(env, "Tried to switch out of user mode\n");
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    if (mode != ARM_CPU_MODE_USR) {
+        cpu_abort(CPU(cpu), "Tried to switch out of user mode\n");
+    }
 }
 
 void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
 {
-    cpu_abort(env, "banked r13 write\n");
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    cpu_abort(CPU(cpu), "banked r13 write\n");
 }
 
 uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
 {
-    cpu_abort(env, "banked r13 read\n");
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
+    cpu_abort(CPU(cpu), "banked r13 read\n");
     return 0;
 }
 
@@ -2762,15 +2786,17 @@
 
 static void v7m_push(CPUARMState *env, uint32_t val)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+
     env->regs[13] -= 4;
     stl_phys(cs->as, env->regs[13], val);
 }
 
 static uint32_t v7m_pop(CPUARMState *env)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(arm_env_get_cpu(env));
     uint32_t val;
+
     val = ldl_phys(cs->as, env->regs[13]);
     env->regs[13] += 4;
     return val;
@@ -2858,7 +2884,7 @@
     uint32_t lr;
     uint32_t addr;
 
-    arm_log_exception(env->exception_index);
+    arm_log_exception(cs->exception_index);
 
     lr = 0xfffffff1;
     if (env->v7m.current_sp)
@@ -2870,7 +2896,7 @@
        handle it.  */
     /* TODO: Need to escalate if the current priority is higher than the
        one we're raising.  */
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXCP_UDEF:
         armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
         return;
@@ -2902,7 +2928,7 @@
         do_v7m_exception_exit(env);
         return;
     default:
-        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
         return; /* Never happens.  Keep compiler happy.  */
     }
 
@@ -2943,10 +2969,10 @@
 
     assert(!IS_M(env));
 
-    arm_log_exception(env->exception_index);
+    arm_log_exception(cs->exception_index);
 
     /* TODO: Vectored interrupt controller.  */
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXCP_UDEF:
         new_mode = ARM_CPU_MODE_UND;
         addr = 0x04;
@@ -3027,7 +3053,7 @@
         offset = 4;
         break;
     default:
-        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
         return; /* Never happens.  Keep compiler happy.  */
     }
     /* High vectors.  */
@@ -3134,7 +3160,7 @@
                             int is_user, hwaddr *phys_ptr,
                             int *prot, target_ulong *page_size)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(arm_env_get_cpu(env));
     int code;
     uint32_t table;
     uint32_t desc;
@@ -3230,7 +3256,7 @@
                             int is_user, hwaddr *phys_ptr,
                             int *prot, target_ulong *page_size)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(arm_env_get_cpu(env));
     int code;
     uint32_t table;
     uint32_t desc;
@@ -3353,7 +3379,7 @@
                               hwaddr *phys_ptr, int *prot,
                               target_ulong *page_size_ptr)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(arm_env_get_cpu(env));
     /* Read an LPAE long-descriptor translation table. */
     MMUFaultType fault_type = translation_fault;
     uint32_t level = 1;
@@ -3633,9 +3659,11 @@
     }
 }
 
-int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
-                              int access_type, int mmu_idx)
+int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
+                             int access_type, int mmu_idx)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
     hwaddr phys_addr;
     target_ulong page_size;
     int prot;
@@ -3648,20 +3676,20 @@
         /* Map a single [sub]page.  */
         phys_addr &= ~(hwaddr)0x3ff;
         address &= ~(uint32_t)0x3ff;
-        tlb_set_page (env, address, phys_addr, prot, mmu_idx, page_size);
+        tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size);
         return 0;
     }
 
     if (access_type == 2) {
         env->cp15.c5_insn = ret;
         env->cp15.c6_insn = address;
-        env->exception_index = EXCP_PREFETCH_ABORT;
+        cs->exception_index = EXCP_PREFETCH_ABORT;
     } else {
         env->cp15.c5_data = ret;
         if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6))
             env->cp15.c5_data |= (1 << 11);
         env->cp15.c6_data = address;
-        env->exception_index = EXCP_DATA_ABORT;
+        cs->exception_index = EXCP_DATA_ABORT;
     }
     return 1;
 }
@@ -3703,6 +3731,8 @@
 
 uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     switch (reg) {
     case 0: /* APSR */
         return xpsr_read(env) & 0xf8000000;
@@ -3733,13 +3763,15 @@
         return env->v7m.control;
     default:
         /* ??? For debugging only.  */
-        cpu_abort(env, "Unimplemented system register read (%d)\n", reg);
+        cpu_abort(CPU(cpu), "Unimplemented system register read (%d)\n", reg);
         return 0;
     }
 }
 
 void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
 {
+    ARMCPU *cpu = arm_env_get_cpu(env);
+
     switch (reg) {
     case 0: /* APSR */
         xpsr_write(env, val, 0xf8000000);
@@ -3802,7 +3834,7 @@
         break;
     default:
         /* ??? For debugging only.  */
-        cpu_abort(env, "Unimplemented system register write (%d)\n", reg);
+        cpu_abort(CPU(cpu), "Unimplemented system register write (%d)\n", reg);
         return;
     }
 }
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 5851e04..21ff58e 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -24,8 +24,11 @@
 
 static void raise_exception(CPUARMState *env, int tt)
 {
-    env->exception_index = tt;
-    cpu_loop_exit(env);
+    ARMCPU *cpu = arm_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
+    cs->exception_index = tt;
+    cpu_loop_exit(cs);
 }
 
 uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
@@ -69,20 +72,24 @@
 #include "exec/softmmu_template.h"
 
 /* try to fill the TLB and return an exception if error. If retaddr is
-   NULL, it means that the function was called in C code (i.e. not
-   from generated code or from helper.c) */
-void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx,
+ * NULL, it means that the function was called in C code (i.e. not
+ * from generated code or from helper.c)
+ */
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = arm_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
+        ARMCPU *cpu = ARM_CPU(cs);
+        CPUARMState *env = &cpu->env;
+
         if (retaddr) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        raise_exception(env, env->exception_index);
+        raise_exception(env, cs->exception_index);
     }
 }
 #endif
@@ -220,24 +227,28 @@
 {
     CPUState *cs = CPU(arm_env_get_cpu(env));
 
-    env->exception_index = EXCP_HLT;
+    cs->exception_index = EXCP_HLT;
     cs->halted = 1;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void HELPER(wfe)(CPUARMState *env)
 {
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+
     /* Don't actually halt the CPU, just yield back to top
      * level loop
      */
-    env->exception_index = EXCP_YIELD;
-    cpu_loop_exit(env);
+    cs->exception_index = EXCP_YIELD;
+    cpu_loop_exit(cs);
 }
 
 void HELPER(exception)(CPUARMState *env, uint32_t excp)
 {
-    env->exception_index = excp;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+
+    cs->exception_index = excp;
+    cpu_loop_exit(cs);
 }
 
 uint32_t HELPER(cpsr_read)(CPUARMState *env)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 37e05e8..2fd9113 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -9061,8 +9061,8 @@
     tcg_clear_temp_count();
 
     do {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
                     gen_exception_insn(dc, 0, EXCP_DEBUG);
                     /* Advance PC so that clearing the breakpoint will
diff --git a/target-arm/translate.c b/target-arm/translate.c
index df259de..fbe513b 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -10733,8 +10733,8 @@
         }
 #endif
 
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
                     gen_exception_insn(dc, 0, EXCP_DEBUG);
                     /* Advance PC so that clearing the breakpoint will
@@ -10803,7 +10803,7 @@
         if (dc->condjmp) {
             /* FIXME:  This can theoretically happen with self-modifying
                code.  */
-            cpu_abort(env, "IO on conditional branch instruction");
+            cpu_abort(cs, "IO on conditional branch instruction");
         }
         gen_io_end();
     }
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 1ac8124..20d8809 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -33,6 +33,11 @@
     cpu->env.pc = value;
 }
 
+static bool cris_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+}
+
 /* CPUClass::reset() */
 static void cris_cpu_reset(CPUState *s)
 {
@@ -44,9 +49,9 @@
     ccc->parent_reset(s);
 
     vr = env->pregs[PR_VR];
-    memset(env, 0, offsetof(CPUCRISState, breakpoints));
+    memset(env, 0, offsetof(CPUCRISState, load_info));
     env->pregs[PR_VR] = vr;
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 
 #if defined(CONFIG_USER_ONLY)
     /* start in user mode with interrupts enabled.  */
@@ -84,18 +89,7 @@
 
 CRISCPU *cpu_cris_init(const char *cpu_model)
 {
-    CRISCPU *cpu;
-    ObjectClass *oc;
-
-    oc = cris_cpu_class_by_name(cpu_model);
-    if (oc == NULL) {
-        return NULL;
-    }
-    cpu = CRIS_CPU(object_new(object_class_get_name(oc)));
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return cpu;
+    return CRIS_CPU(cpu_generic_init(TYPE_CRIS_CPU, cpu_model));
 }
 
 /* Sort alphabetically by VR. */
@@ -283,12 +277,15 @@
     cc->reset = cris_cpu_reset;
 
     cc->class_by_name = cris_cpu_class_by_name;
+    cc->has_work = cris_cpu_has_work;
     cc->do_interrupt = cris_cpu_do_interrupt;
     cc->dump_state = cris_cpu_dump_state;
     cc->set_pc = cris_cpu_set_pc;
     cc->gdb_read_register = cris_cpu_gdb_read_register;
     cc->gdb_write_register = cris_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = cris_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
 #endif
 
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 1d7d80d..b88c147 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -171,8 +171,8 @@
 
 	CPU_COMMON
 
-	/* Members after CPU_COMMON are preserved across resets.  */
-	void *load_info;
+    /* Members from load_info on are preserved across resets.  */
+    void *load_info;
 } CPUCRISState;
 
 #include "cpu-qom.h"
@@ -247,9 +247,8 @@
 	return !!(env->pregs[PR_CCS] & U_FLAG);
 }
 
-int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw,
+int cris_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
                               int mmu_idx);
-#define cpu_handle_mmu_fault cpu_cris_handle_mmu_fault
 
 /* Support function regs.  */
 #define SFR_RW_GC_CFG      0][0
@@ -276,11 +275,6 @@
 #define cpu_list cris_cpu_list
 void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
-}
-
 #include "exec/exec-all.h"
 
 #endif
diff --git a/target-cris/helper.c b/target-cris/helper.c
index c940582..4092d27 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -41,7 +41,7 @@
     CRISCPU *cpu = CRIS_CPU(cs);
     CPUCRISState *env = &cpu->env;
 
-    env->exception_index = -1;
+    cs->exception_index = -1;
     env->pregs[PR_ERP] = env->pc;
 }
 
@@ -50,14 +50,14 @@
     cris_cpu_do_interrupt(cs);
 }
 
-int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw,
+int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                               int mmu_idx)
 {
-    CRISCPU *cpu = cris_env_get_cpu(env);
+    CRISCPU *cpu = CRIS_CPU(cs);
 
-    env->exception_index = 0xaa;
-    env->pregs[PR_EDA] = address;
-    cpu_dump_state(CPU(cpu), stderr, fprintf, 0);
+    cs->exception_index = 0xaa;
+    cpu->env.pregs[PR_EDA] = address;
+    cpu_dump_state(cs, stderr, fprintf, 0);
     return 1;
 }
 
@@ -73,28 +73,30 @@
     env->pregs[PR_CCS] = ccs;
 }
 
-int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw,
+int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                               int mmu_idx)
 {
-    D(CPUState *cpu = CPU(cris_env_get_cpu(env)));
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &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));
+    D(printf("%s addr=%" VADDR_PRIx " 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,
+        if (cs->exception_index == EXCP_BUSFAULT) {
+            cpu_abort(cs,
                       "CRIS: Illegal recursive bus fault."
-                      "addr=%x rw=%d\n",
+                      "addr=%" VADDR_PRIx " rw=%d\n",
                       address, rw);
         }
 
         env->pregs[PR_EDA] = address;
-        env->exception_index = EXCP_BUSFAULT;
+        cs->exception_index = EXCP_BUSFAULT;
         env->fault_vector = res.bf_vec;
         r = 1;
     } else {
@@ -104,13 +106,13 @@
          */
         phy = res.phy & ~0x80000000;
         prot = res.prot;
-        tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
+        tlb_set_page(cs, 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,
+        D_LOG("%s returns %d irqreq=%x addr=%" VADDR_PRIx " phy=%x vec=%x"
+              " pc=%x\n", __func__, r, cs->interrupt_request, address, res.phy,
               res.bf_vec, env->pc);
     }
     return r;
@@ -123,16 +125,16 @@
     int ex_vec = -1;
 
     D_LOG("exception index=%d interrupt_req=%d\n",
-          env->exception_index,
+          cs->exception_index,
           cs->interrupt_request);
 
     if (env->dslot) {
         /* CRISv10 never takes interrupts while in a delay-slot.  */
-        cpu_abort(env, "CRIS: Interrupt on delay-slot\n");
+        cpu_abort(cs, "CRIS: Interrupt on delay-slot\n");
     }
 
     assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXCP_BREAK:
         /* These exceptions are genereated by the core itself.
            ERP should point to the insn following the brk.  */
@@ -148,7 +150,7 @@
         break;
 
     case EXCP_BUSFAULT:
-        cpu_abort(env, "Unhandled busfault");
+        cpu_abort(cs, "Unhandled busfault");
         break;
 
     default:
@@ -185,10 +187,10 @@
     int ex_vec = -1;
 
     D_LOG("exception index=%d interrupt_req=%d\n",
-          env->exception_index,
+          cs->exception_index,
           cs->interrupt_request);
 
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXCP_BREAK:
         /* These exceptions are genereated by the core itself.
            ERP should point to the insn following the brk.  */
@@ -251,7 +253,7 @@
 
     /* Clear the excption_index to avoid spurios hw_aborts for recursive
        bus faults.  */
-    env->exception_index = -1;
+    cs->exception_index = -1;
 
     D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
           __func__, env->pc, ex_vec,
diff --git a/target-cris/mmu.c b/target-cris/mmu.c
index 512e28b..1c95a41 100644
--- a/target-cris/mmu.c
+++ b/target-cris/mmu.c
@@ -290,6 +290,7 @@
 
 void cris_mmu_flush_pid(CPUCRISState *env, uint32_t pid)
 {
+    CRISCPU *cpu = cris_env_get_cpu(env);
 	target_ulong vaddr;
 	unsigned int idx;
 	uint32_t lo, hi;
@@ -315,7 +316,7 @@
 					vaddr = tlb_vpn << TARGET_PAGE_BITS;
 					D_LOG("flush pid=%x vaddr=%x\n", 
 						  pid, vaddr);
-					tlb_flush_page(env, vaddr);
+                    tlb_flush_page(CPU(cpu), vaddr);
 				}
 			}
 		}
diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c
index b580513..bd9a583 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -54,23 +54,25 @@
 /* Try to fill the TLB and return an exception if error. If retaddr is
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
-void tlb_fill(CPUCRISState *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
     int ret;
 
     D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__,
           env->pc, env->pregs[PR_EDA], (void *)retaddr);
-    ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = cris_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
-            if (cpu_restore_state(env, retaddr)) {
+            if (cpu_restore_state(cs, retaddr)) {
 		/* Evaluate flags after retranslation.  */
                 helper_top_evaluate_flags(env);
             }
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 
@@ -78,8 +80,10 @@
 
 void helper_raise_exception(CPUCRISState *env, uint32_t index)
 {
-	env->exception_index = index;
-        cpu_loop_exit(env);
+    CPUState *cs = CPU(cris_env_get_cpu(env));
+
+    cs->exception_index = index;
+    cpu_loop_exit(cs);
 }
 
 void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid)
@@ -94,8 +98,11 @@
 void helper_spc_write(CPUCRISState *env, uint32_t new_spc)
 {
 #if !defined(CONFIG_USER_ONLY)
-	tlb_flush_page(env, env->pregs[PR_SPC]);
-	tlb_flush_page(env, new_spc);
+    CRISCPU *cpu = cris_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
+    tlb_flush_page(cs, env->pregs[PR_SPC]);
+    tlb_flush_page(cs, new_spc);
 #endif
 }
 
@@ -110,6 +117,9 @@
 
 void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg)
 {
+#if !defined(CONFIG_USER_ONLY)
+    CRISCPU *cpu = cris_env_get_cpu(env);
+#endif
 	uint32_t srs;
 	srs = env->pregs[PR_SRS];
 	srs &= 3;
@@ -151,7 +161,7 @@
 			D_LOG("tlb flush vaddr=%x v=%d pc=%x\n", 
 				  vaddr, tlb_v, env->pc);
 			if (tlb_v) {
-				tlb_flush_page(env, vaddr);
+                tlb_flush_page(CPU(cpu), vaddr);
 			}
 		}
 	}
diff --git a/target-cris/translate.c b/target-cris/translate.c
index f990d59..724f920 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -74,7 +74,7 @@
 
 /* This is the state at translation time.  */
 typedef struct DisasContext {
-    CPUCRISState *env;
+    CRISCPU *cpu;
     target_ulong pc, ppc;
 
     /* Decoder.  */
@@ -129,7 +129,7 @@
 {
     printf("BUG: pc=%x %s %d\n", dc->pc, file, line);
     qemu_log("BUG: pc=%x %s %d\n", dc->pc, file, line);
-    cpu_abort(dc->env, "%s:%d\n", file, line);
+    cpu_abort(CPU(dc->cpu), "%s:%d\n", file, line);
 }
 
 static const char *regnames[] =
@@ -272,7 +272,7 @@
         break;
     }
     default:
-        cpu_abort(dc->env, "Invalid fetch size %d\n", size);
+        cpu_abort(CPU(dc->cpu), "Invalid fetch size %d\n", size);
         break;
     }
     return r;
@@ -1125,7 +1125,7 @@
 
 static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr)
 {
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     /* If we get a fault on a delayslot we must keep the jmp state in
        the cpu-state to be able to re-execute the jmp.  */
@@ -1139,7 +1139,7 @@
 static void gen_load(DisasContext *dc, TCGv dst, TCGv addr, 
              unsigned int size, int sign)
 {
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     /* If we get a fault on a delayslot we must keep the jmp state in
        the cpu-state to be able to re-execute the jmp.  */
@@ -1154,7 +1154,7 @@
 static void gen_store (DisasContext *dc, TCGv addr, TCGv val,
                unsigned int size)
 {
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     /* If we get a fault on a delayslot we must keep the jmp state in
        the cpu-state to be able to re-execute the jmp.  */
@@ -3089,10 +3089,11 @@
 
 static void check_breakpoint(CPUCRISState *env, DisasContext *dc)
 {
+    CPUState *cs = CPU(cris_env_get_cpu(env));
     CPUBreakpoint *bp;
 
-    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+    if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == dc->pc) {
                 cris_evaluate_flags(dc);
                 tcg_gen_movi_tl(env_pc, dc->pc);
@@ -3169,7 +3170,7 @@
      * delayslot, like in real hw.
      */
     pc_start = tb->pc & ~1;
-    dc->env = env;
+    dc->cpu = cpu;
     dc->tb = tb;
 
     gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
@@ -3390,7 +3391,7 @@
 #if !DISAS_CRIS
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
         log_target_disas(env, pc_start, dc->pc - pc_start,
-                                 dc->env->pregs[PR_VR]);
+                         env->pregs[PR_VR]);
         qemu_log("\nisize=%d osize=%td\n",
             dc->pc - pc_start, tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf);
     }
diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c
index d6ef084..2ad2b14 100644
--- a/target-cris/translate_v10.c
+++ b/target-cris/translate_v10.c
@@ -96,7 +96,7 @@
 static void gen_store_v10(DisasContext *dc, TCGv addr, TCGv val,
                        unsigned int size)
 {
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     /* If we get a fault on a delayslot we must keep the jmp state in
        the cpu-state to be able to re-execute the jmp.  */
@@ -340,7 +340,7 @@
         default:
             LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n",
                      dc->pc, dc->mode, dc->opcode, dc->src, dc->dst);
-            cpu_abort(dc->env, "Unhandled quickimm\n");
+            cpu_abort(CPU(dc->cpu), "Unhandled quickimm\n");
             break;
     }
     return 2;
@@ -651,7 +651,7 @@
                     case 2: tmp = 1; break;
                     case 1: tmp = 0; break;
                     default:
-                        cpu_abort(dc->env, "Unhandled BIAP");
+                        cpu_abort(CPU(dc->cpu), "Unhandled BIAP");
                         break;
                 }
 
@@ -669,7 +669,7 @@
             default:
                 LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc,
                          dc->opcode, dc->src, dc->dst);
-                cpu_abort(dc->env, "Unhandled opcode");
+                cpu_abort(CPU(dc->cpu), "Unhandled opcode");
                 break;
         }
     } else {
@@ -745,7 +745,7 @@
             default:
                 LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc,
                          dc->opcode, dc->src, dc->dst);
-                cpu_abort(dc->env, "Unhandled opcode");
+                cpu_abort(CPU(dc->cpu), "Unhandled opcode");
                 break;
         }
     }
@@ -1006,7 +1006,7 @@
     if (!dc->postinc && (dc->ir & (1 << 11))) {
         int simm = dc->ir & 0xff;
 
-        /* cpu_abort(dc->env, "Unhandled opcode"); */
+        /* cpu_abort(CPU(dc->cpu), "Unhandled opcode"); */
         /* sign extended.  */
         simm = (int8_t)simm;
 
@@ -1105,7 +1105,7 @@
             default:
                 LOG_DIS("pc=%x var-ind.%d %d r%d r%d\n",
                           dc->pc, size, dc->opcode, dc->src, dc->dst);
-                cpu_abort(dc->env, "Unhandled opcode");
+                cpu_abort(CPU(dc->cpu), "Unhandled opcode");
                 break;
         }
         return insn_len;
@@ -1198,7 +1198,7 @@
             break;
         default:
             LOG_DIS("ERROR pc=%x opcode=%d\n", dc->pc, dc->opcode);
-            cpu_abort(dc->env, "Unhandled opcode");
+            cpu_abort(CPU(dc->cpu), "Unhandled opcode");
             break;
     }
 
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 722f11a..e9b3d57 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -38,7 +38,17 @@
     OBJECT_GET_CLASS(X86CPUClass, (obj), TYPE_X86_CPU)
 
 /**
+ * X86CPUDefinition:
+ *
+ * CPU model definition data that was not converted to QOM per-subclass
+ * property defaults yet.
+ */
+typedef struct X86CPUDefinition X86CPUDefinition;
+
+/**
  * X86CPUClass:
+ * @cpu_def: CPU model definition
+ * @kvm_required: Whether CPU model requires KVM to be enabled.
  * @parent_realize: The parent class' realize handler.
  * @parent_reset: The parent class' reset handler.
  *
@@ -49,6 +59,11 @@
     CPUClass parent_class;
     /*< public >*/
 
+    /* Should be eventually replaced by subclass-specific property defaults. */
+    X86CPUDefinition *cpu_def;
+
+    bool kvm_required;
+
     DeviceRealize parent_realize;
     void (*parent_reset)(CPUState *cpu);
 } X86CPUClass;
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 5cfe450..e7e62c5 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -358,17 +358,23 @@
     FeatureWord feat_word;
 } model_features_t;
 
-static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) |
+/* KVM-specific features that are automatically added to all CPU models
+ * when KVM is enabled.
+ */
+static uint32_t kvm_default_features[FEATURE_WORDS] = {
+    [FEAT_KVM] = (1 << KVM_FEATURE_CLOCKSOURCE) |
         (1 << KVM_FEATURE_NOP_IO_DELAY) |
         (1 << KVM_FEATURE_CLOCKSOURCE2) |
         (1 << KVM_FEATURE_ASYNC_PF) |
         (1 << KVM_FEATURE_STEAL_TIME) |
         (1 << KVM_FEATURE_PV_EOI) |
-        (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
+        (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT),
+    [FEAT_1_ECX] = CPUID_EXT_X2APIC,
+};
 
-void disable_kvm_pv_eoi(void)
+void x86_cpu_compat_disable_kvm_features(FeatureWord w, uint32_t features)
 {
-    kvm_default_features &= ~(1UL << KVM_FEATURE_PV_EOI);
+    kvm_default_features[w] &= ~features;
 }
 
 void host_cpuid(uint32_t function, uint32_t count,
@@ -484,7 +490,35 @@
     }
 }
 
-typedef struct x86_def_t {
+/* CPU class name definitions: */
+
+#define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU
+#define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
+
+/* Return type name for a given CPU model name
+ * Caller is responsible for freeing the returned string.
+ */
+static char *x86_cpu_type_name(const char *model_name)
+{
+    return g_strdup_printf(X86_CPU_TYPE_NAME("%s"), model_name);
+}
+
+static ObjectClass *x86_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+    char *typename;
+
+    if (cpu_model == NULL) {
+        return NULL;
+    }
+
+    typename = x86_cpu_type_name(cpu_model);
+    oc = object_class_by_name(typename);
+    g_free(typename);
+    return oc;
+}
+
+struct X86CPUDefinition {
     const char *name;
     uint32_t level;
     uint32_t xlevel;
@@ -497,7 +531,7 @@
     FeatureWordArray features;
     char model_id[48];
     bool cache_info_passthrough;
-} x86_def_t;
+};
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
 #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
@@ -547,9 +581,7 @@
           CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
           CPUID_7_0_EBX_RDSEED */
 
-/* built-in CPU model definitions
- */
-static x86_def_t builtin_x86_defs[] = {
+static X86CPUDefinition builtin_x86_defs[] = {
     {
         .name = "qemu64",
         .level = 4,
@@ -1108,7 +1140,7 @@
 void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
                                  uint32_t feat_add, uint32_t feat_remove)
 {
-    x86_def_t *def;
+    X86CPUDefinition *def;
     int i;
     for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
         def = &builtin_x86_defs[i];
@@ -1119,6 +1151,8 @@
     }
 }
 
+#ifdef CONFIG_KVM
+
 static int cpu_x86_fill_model_id(char *str)
 {
     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -1134,44 +1168,68 @@
     return 0;
 }
 
-/* Fill a x86_def_t struct with information about the host CPU, and
- * the CPU features supported by the host hardware + host kernel
+static X86CPUDefinition host_cpudef;
+
+/* class_init for the "host" CPU model
  *
- * This function may be called only if KVM is enabled.
+ * This function may be called before KVM is initialized.
  */
-static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
+static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
 {
-    KVMState *s = kvm_state;
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
 
+    xcc->kvm_required = true;
+
+    host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
+    x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
+
+    host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+    host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+    host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+    host_cpudef.stepping = eax & 0x0F;
+
+    cpu_x86_fill_model_id(host_cpudef.model_id);
+
+    xcc->cpu_def = &host_cpudef;
+    host_cpudef.cache_info_passthrough = true;
+
+    /* level, xlevel, xlevel2, and the feature words are initialized on
+     * instance_init, because they require KVM to be initialized.
+     */
+}
+
+static void host_x86_cpu_initfn(Object *obj)
+{
+    X86CPU *cpu = X86_CPU(obj);
+    CPUX86State *env = &cpu->env;
+    KVMState *s = kvm_state;
+    FeatureWord w;
+
     assert(kvm_enabled());
 
-    x86_cpu_def->name = "host";
-    x86_cpu_def->cache_info_passthrough = true;
-    host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
-    x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
+    env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+    env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
+    env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
 
-    host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
-    x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
-    x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
-    x86_cpu_def->stepping = eax & 0x0F;
-
-    x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
-    x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
-    x86_cpu_def->xlevel2 =
-        kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
-
-    cpu_x86_fill_model_id(x86_cpu_def->model_id);
-
-    FeatureWord w;
     for (w = 0; w < FEATURE_WORDS; w++) {
         FeatureWordInfo *wi = &feature_word_info[w];
-        x86_cpu_def->features[w] =
+        env->features[w] =
             kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, wi->cpuid_ecx,
                                          wi->cpuid_reg);
     }
+    object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
 }
 
+static const TypeInfo host_x86_cpu_type_info = {
+    .name = X86_CPU_TYPE_NAME("host"),
+    .parent = TYPE_X86_CPU,
+    .instance_init = host_x86_cpu_initfn,
+    .class_init = host_x86_cpu_class_init,
+};
+
+#endif
+
 static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
 {
     int i;
@@ -1582,32 +1640,6 @@
     .set   = x86_set_hv_spinlocks,
 };
 
-static int cpu_x86_find_by_name(X86CPU *cpu, x86_def_t *x86_cpu_def,
-                                const char *name)
-{
-    x86_def_t *def;
-    int i;
-
-    if (name == NULL) {
-        return -1;
-    }
-    if (kvm_enabled() && strcmp(name, "host") == 0) {
-        kvm_cpu_fill_host(x86_cpu_def);
-        object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
-        return 0;
-    }
-
-    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
-        def = &builtin_x86_defs[i];
-        if (strcmp(name, def->name) == 0) {
-            memcpy(x86_cpu_def, def, sizeof(*def));
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
 /* Convert all '_' in a feature string option name to '-', to make feature
  * name conform to QOM property naming rule, which uses '-' instead of '_'.
  */
@@ -1620,8 +1652,10 @@
 
 /* Parse "+feature,-feature,feature=foo" CPU feature string
  */
-static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp)
+static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
+                                     Error **errp)
 {
+    X86CPU *cpu = X86_CPU(cs);
     char *featurestr; /* Single 'key=value" string being parsed */
     /* Features to be added */
     FeatureWordArray plus_features = { 0 };
@@ -1629,6 +1663,7 @@
     FeatureWordArray minus_features = { 0 };
     uint32_t numvalue;
     CPUX86State *env = &cpu->env;
+    Error *local_err = NULL;
 
     featurestr = features ? strtok(features, ",") : NULL;
 
@@ -1647,16 +1682,16 @@
 
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
-                    error_setg(errp, "bad numerical value %s", val);
+                    error_setg(&local_err, "bad numerical value %s", val);
                     goto out;
                 }
                 if (numvalue < 0x80000000) {
-                    fprintf(stderr, "xlevel value shall always be >= 0x80000000"
-                            ", fixup will be removed in future versions\n");
+                    error_report("xlevel value shall always be >= 0x80000000"
+                                 ", fixup will be removed in future versions");
                     numvalue += 0x80000000;
                 }
                 snprintf(num, sizeof(num), "%" PRIu32, numvalue);
-                object_property_parse(OBJECT(cpu), num, featurestr, errp);
+                object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
             } else if (!strcmp(featurestr, "tsc-freq")) {
                 int64_t tsc_freq;
                 char *err;
@@ -1665,36 +1700,38 @@
                 tsc_freq = strtosz_suffix_unit(val, &err,
                                                STRTOSZ_DEFSUFFIX_B, 1000);
                 if (tsc_freq < 0 || *err) {
-                    error_setg(errp, "bad numerical value %s", val);
+                    error_setg(&local_err, "bad numerical value %s", val);
                     goto out;
                 }
                 snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
-                object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp);
+                object_property_parse(OBJECT(cpu), num, "tsc-frequency",
+                                      &local_err);
             } else if (!strcmp(featurestr, "hv-spinlocks")) {
                 char *err;
                 const int min = 0xFFF;
                 char num[32];
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
-                    error_setg(errp, "bad numerical value %s", val);
+                    error_setg(&local_err, "bad numerical value %s", val);
                     goto out;
                 }
                 if (numvalue < min) {
-                    fprintf(stderr, "hv-spinlocks value shall always be >= 0x%x"
-                            ", fixup will be removed in future versions\n",
+                    error_report("hv-spinlocks value shall always be >= 0x%x"
+                            ", fixup will be removed in future versions",
                             min);
                     numvalue = min;
                 }
                 snprintf(num, sizeof(num), "%" PRId32, numvalue);
-                object_property_parse(OBJECT(cpu), num, featurestr, errp);
+                object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
             } else {
-                object_property_parse(OBJECT(cpu), val, featurestr, errp);
+                object_property_parse(OBJECT(cpu), val, featurestr, &local_err);
             }
         } else {
             feat2prop(featurestr);
-            object_property_parse(OBJECT(cpu), "on", featurestr, errp);
+            object_property_parse(OBJECT(cpu), "on", featurestr, &local_err);
         }
-        if (error_is_set(errp)) {
+        if (local_err) {
+            error_propagate(errp, local_err);
             goto out;
         }
         featurestr = strtok(NULL, ",");
@@ -1753,7 +1790,7 @@
 /* generate CPU information. */
 void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
-    x86_def_t *def;
+    X86CPUDefinition *def;
     char buf[256];
     int i;
 
@@ -1780,7 +1817,7 @@
 CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
-    x86_def_t *def;
+    X86CPUDefinition *def;
     int i;
 
     for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
@@ -1817,17 +1854,13 @@
     }
 }
 
-static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
+/* Load data from X86CPUDefinition
+ */
+static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
 {
     CPUX86State *env = &cpu->env;
-    x86_def_t def1, *def = &def1;
-
-    memset(def, 0, sizeof(*def));
-
-    if (cpu_x86_find_by_name(cpu, def, name) < 0) {
-        error_setg(errp, "Unable to find CPU definition: %s", name);
-        return;
-    }
+    const char *vendor;
+    char host_vendor[CPUID_VENDOR_SZ + 1];
 
     object_property_set_int(OBJECT(cpu), def->level, "level", errp);
     object_property_set_int(OBJECT(cpu), def->family, "family", errp);
@@ -1847,10 +1880,14 @@
 
     object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
 
-    /* Special cases not set in the x86_def_t structs: */
+    /* Special cases not set in the X86CPUDefinition structs: */
     if (kvm_enabled()) {
-        env->features[FEAT_KVM] |= kvm_default_features;
+        FeatureWord w;
+        for (w = 0; w < FEATURE_WORDS; w++) {
+            env->features[w] |= kvm_default_features[w];
+        }
     }
+
     env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
 
     /* sysenter isn't supported in compatibility mode on AMD,
@@ -1860,8 +1897,7 @@
      * KVM's sysenter/syscall emulation in compatibility mode and
      * when doing cross vendor migration
      */
-    const char *vendor = def->vendor;
-    char host_vendor[CPUID_VENDOR_SZ + 1];
+    vendor = def->vendor;
     if (kvm_enabled()) {
         uint32_t  ebx = 0, ecx = 0, edx = 0;
         host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
@@ -1877,9 +1913,10 @@
                        Error **errp)
 {
     X86CPU *cpu = NULL;
+    X86CPUClass *xcc;
+    ObjectClass *oc;
     gchar **model_pieces;
     char *name, *features;
-    char *typename;
     Error *error = NULL;
 
     model_pieces = g_strsplit(cpu_model, ",", 2);
@@ -1890,7 +1927,20 @@
     name = model_pieces[0];
     features = model_pieces[1];
 
-    cpu = X86_CPU(object_new(TYPE_X86_CPU));
+    oc = x86_cpu_class_by_name(name);
+    if (oc == NULL) {
+        error_setg(&error, "Unable to find CPU definition: %s", name);
+        goto out;
+    }
+    xcc = X86_CPU_CLASS(oc);
+
+    if (xcc->kvm_required && !kvm_enabled()) {
+        error_setg(&error, "CPU model '%s' requires KVM", name);
+        goto out;
+    }
+
+    cpu = X86_CPU(object_new(object_class_get_name(oc)));
+
 #ifndef CONFIG_USER_ONLY
     if (icc_bridge == NULL) {
         error_setg(&error, "Invalid icc-bridge value");
@@ -1900,20 +1950,7 @@
     object_unref(OBJECT(cpu));
 #endif
 
-    cpu_x86_register(cpu, name, &error);
-    if (error) {
-        goto out;
-    }
-
-    /* Emulate per-model subclasses for global properties */
-    typename = g_strdup_printf("%s-" TYPE_X86_CPU, name);
-    qdev_prop_set_globals_for_type(DEVICE(cpu), typename, &error);
-    g_free(typename);
-    if (error) {
-        goto out;
-    }
-
-    cpu_x86_parse_featurestr(cpu, features, &error);
+    x86_cpu_parse_featurestr(CPU(cpu), features, &error);
     if (error) {
         goto out;
     }
@@ -1921,8 +1958,10 @@
 out:
     if (error != NULL) {
         error_propagate(errp, error);
-        object_unref(OBJECT(cpu));
-        cpu = NULL;
+        if (cpu) {
+            object_unref(OBJECT(cpu));
+            cpu = NULL;
+        }
     }
     g_strfreev(model_pieces);
     return cpu;
@@ -1952,6 +1991,28 @@
     return cpu;
 }
 
+static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
+{
+    X86CPUDefinition *cpudef = data;
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
+
+    xcc->cpu_def = cpudef;
+}
+
+static void x86_register_cpudef_type(X86CPUDefinition *def)
+{
+    char *typename = x86_cpu_type_name(def->name);
+    TypeInfo ti = {
+        .name = typename,
+        .parent = TYPE_X86_CPU,
+        .class_init = x86_cpu_cpudef_class_init,
+        .class_data = def,
+    };
+
+    type_register(&ti);
+    g_free(typename);
+}
+
 #if !defined(CONFIG_USER_ONLY)
 
 void cpu_clear_apic_feature(CPUX86State *env)
@@ -1969,7 +2030,7 @@
     static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" };
 
     for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
-        x86_def_t *def = &builtin_x86_defs[i];
+        X86CPUDefinition *def = &builtin_x86_defs[i];
 
         /* Look for specific "cpudef" models that */
         /* have the QEMU version in .model_id */
@@ -2349,9 +2410,9 @@
     xcc->parent_reset(s);
 
 
-    memset(env, 0, offsetof(CPUX86State, breakpoints));
+    memset(env, 0, offsetof(CPUX86State, pat));
 
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 
     env->old_exception = -1;
 
@@ -2412,8 +2473,8 @@
     memset(env->dr, 0, sizeof(env->dr));
     env->dr[6] = DR6_FIXED_1;
     env->dr[7] = DR7_FIXED_1;
-    cpu_breakpoint_remove_all(env, BP_CPU);
-    cpu_watchpoint_remove_all(env, BP_CPU);
+    cpu_breakpoint_remove_all(s, BP_CPU);
+    cpu_watchpoint_remove_all(s, BP_CPU);
 
     env->tsc_adjust = 0;
     env->tsc = 0;
@@ -2613,6 +2674,7 @@
 {
     CPUState *cs = CPU(obj);
     X86CPU *cpu = X86_CPU(obj);
+    X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
     CPUX86State *env = &cpu->env;
     static int inited;
 
@@ -2656,6 +2718,8 @@
     cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
     env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
 
+    x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
+
     /* init various static tables used in TCG mode */
     if (tcg_enabled() && !inited) {
         inited = 1;
@@ -2695,6 +2759,20 @@
     cpu->env.eip = tb->pc - tb->cs_base;
 }
 
+static bool x86_cpu_has_work(CPUState *cs)
+{
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
+    return ((cs->interrupt_request & (CPU_INTERRUPT_HARD |
+                                      CPU_INTERRUPT_POLL)) &&
+            (env->eflags & IF_MASK)) ||
+           (cs->interrupt_request & (CPU_INTERRUPT_NMI |
+                                     CPU_INTERRUPT_INIT |
+                                     CPU_INTERRUPT_SIPI |
+                                     CPU_INTERRUPT_MCE));
+}
+
 static Property x86_cpu_properties[] = {
     DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
     { .name  = "hv-spinlocks", .info  = &qdev_prop_spinlocks },
@@ -2721,6 +2799,9 @@
     cc->reset = x86_cpu_reset;
     cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP;
 
+    cc->class_by_name = x86_cpu_class_by_name;
+    cc->parse_features = x86_cpu_parse_featurestr;
+    cc->has_work = x86_cpu_has_work;
     cc->do_interrupt = x86_cpu_do_interrupt;
     cc->dump_state = x86_cpu_dump_state;
     cc->set_pc = x86_cpu_set_pc;
@@ -2729,7 +2810,9 @@
     cc->gdb_write_register = x86_cpu_gdb_write_register;
     cc->get_arch_id = x86_cpu_get_arch_id;
     cc->get_paging_enabled = x86_cpu_get_paging_enabled;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = x86_cpu_handle_mmu_fault;
+#else
     cc->get_memory_mapping = x86_cpu_get_memory_mapping;
     cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
     cc->write_elf64_note = x86_cpu_write_elf64_note;
@@ -2746,14 +2829,22 @@
     .parent = TYPE_CPU,
     .instance_size = sizeof(X86CPU),
     .instance_init = x86_cpu_initfn,
-    .abstract = false,
+    .abstract = true,
     .class_size = sizeof(X86CPUClass),
     .class_init = x86_cpu_common_class_init,
 };
 
 static void x86_cpu_register_types(void)
 {
+    int i;
+
     type_register_static(&x86_cpu_type_info);
+    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
+        x86_register_cpudef_type(&builtin_x86_defs[i]);
+    }
+#ifdef CONFIG_KVM
+    type_register_static(&host_x86_cpu_type_info);
+#endif
 }
 
 type_init(x86_cpu_register_types)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0014acc..4d1374c 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -875,8 +875,8 @@
     target_ulong exception_next_eip;
     target_ulong dr[8]; /* debug registers */
     union {
-        CPUBreakpoint *cpu_breakpoint[4];
-        CPUWatchpoint *cpu_watchpoint[4];
+        struct CPUBreakpoint *cpu_breakpoint[4];
+        struct CPUWatchpoint *cpu_watchpoint[4];
     }; /* break/watchpoints for dr[0..3] */
     uint32_t smbase;
     int old_exception;  /* exception in flight */
@@ -887,6 +887,7 @@
 
     CPU_COMMON
 
+    /* Fields from here on are preserved across CPU reset. */
     uint64_t pat;
 
     /* processor features (e.g. for CPUID insn) */
@@ -1067,9 +1068,8 @@
                 uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
 
 /* helper.c */
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+int x86_cpu_handle_mmu_fault(CPUState *cpu, vaddr addr,
                              int is_write, int mmu_idx);
-#define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault
 void x86_cpu_set_a20(X86CPU *cpu, int a20_state);
 
 static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index)
@@ -1186,20 +1186,6 @@
 #include "hw/i386/apic.h"
 #endif
 
-static inline bool cpu_has_work(CPUState *cs)
-{
-    X86CPU *cpu = X86_CPU(cs);
-    CPUX86State *env = &cpu->env;
-
-    return ((cs->interrupt_request & (CPU_INTERRUPT_HARD |
-                                      CPU_INTERRUPT_POLL)) &&
-            (env->eflags & IF_MASK)) ||
-           (cs->interrupt_request & (CPU_INTERRUPT_NMI |
-                                     CPU_INTERRUPT_INIT |
-                                     CPU_INTERRUPT_SIPI |
-                                     CPU_INTERRUPT_MCE));
-}
-
 #include "exec/exec-all.h"
 
 static inline void cpu_get_tb_cpu_state(CPUX86State *env, target_ulong *pc,
@@ -1276,11 +1262,11 @@
 
 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
 
-void disable_kvm_pv_eoi(void);
-
 void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
                                  uint32_t feat_add, uint32_t feat_remove);
 
+void x86_cpu_compat_disable_kvm_features(FeatureWord w, uint32_t features);
+
 
 /* Return name of 32-bit register, from a R_* constant */
 const char *get_register_name_32(unsigned int reg);
diff --git a/target-i386/excp_helper.c b/target-i386/excp_helper.c
index 5319aef..f337fd2 100644
--- a/target-i386/excp_helper.c
+++ b/target-i386/excp_helper.c
@@ -94,6 +94,8 @@
                                            int is_int, int error_code,
                                            int next_eip_addend)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
     if (!is_int) {
         cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
                                       error_code);
@@ -102,11 +104,11 @@
         cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0);
     }
 
-    env->exception_index = intno;
+    cs->exception_index = intno;
     env->error_code = error_code;
     env->exception_is_int = is_int;
     env->exception_next_eip = env->eip + next_eip_addend;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 /* shortcuts to generate exceptions */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 55c0457..4f447b8 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -385,22 +385,25 @@
 
     a20_state = (a20_state != 0);
     if (a20_state != ((env->a20_mask >> 20) & 1)) {
+        CPUState *cs = CPU(cpu);
+
 #if defined(DEBUG_MMU)
         printf("A20 update: a20=%d\n", a20_state);
 #endif
         /* if the cpu is currently executing code, we must unlink it and
            all the potentially executing TB */
-        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_EXITTB);
+        cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
 
         /* when a20 is changed, all the MMU mappings are invalid, so
            we must flush everything */
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
         env->a20_mask = ~(1 << 20) | (a20_state << 20);
     }
 }
 
 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     int pe_state;
 
 #if defined(DEBUG_MMU)
@@ -408,7 +411,7 @@
 #endif
     if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
         (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 
 #ifdef TARGET_X86_64
@@ -444,24 +447,28 @@
    the PDPT */
 void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
+
     env->cr[3] = new_cr3;
     if (env->cr[0] & CR0_PG_MASK) {
 #if defined(DEBUG_MMU)
         printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
 #endif
-        tlb_flush(env, 0);
+        tlb_flush(CPU(cpu), 0);
     }
 }
 
 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
+
 #if defined(DEBUG_MMU)
     printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
 #endif
     if ((new_cr4 ^ env->cr[4]) &
         (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK |
          CR4_SMEP_MASK | CR4_SMAP_MASK)) {
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
     /* SSE handling */
     if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
@@ -485,15 +492,18 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr,
                              int is_write, int mmu_idx)
 {
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
     /* user mode only emulation */
     is_write &= 1;
     env->cr[2] = addr;
     env->error_code = (is_write << PG_ERROR_W_BIT);
     env->error_code |= PG_ERROR_U_MASK;
-    env->exception_index = EXCP0E_PAGE;
+    cs->exception_index = EXCP0E_PAGE;
     return 1;
 }
 
@@ -508,14 +518,15 @@
 # endif
 
 /* return value:
-   -1 = cannot handle fault
-   0  = nothing more to do
-   1  = generate PF fault
-*/
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+ * -1 = cannot handle fault
+ * 0  = nothing more to do
+ * 1  = generate PF fault
+ */
+int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr,
                              int is_write1, int mmu_idx)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
     uint64_t ptep, pte;
     target_ulong pde_addr, pte_addr;
     int error_code, is_dirty, prot, page_size, is_write, is_user;
@@ -525,7 +536,7 @@
 
     is_user = mmu_idx == MMU_USER_IDX;
 #if defined(DEBUG_MMU)
-    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
+    printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
            addr, is_write1, is_user, env->eip);
 #endif
     is_write = is_write1 & 1;
@@ -557,7 +568,7 @@
             sext = (int64_t)addr >> 47;
             if (sext != 0 && sext != -1) {
                 env->error_code = 0;
-                env->exception_index = EXCP0D_GPF;
+                cs->exception_index = EXCP0D_GPF;
                 return 1;
             }
 
@@ -866,7 +877,7 @@
     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
     vaddr = virt_addr + page_offset;
 
-    tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+    tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
     return 0;
  do_fault_protect:
     error_code = PG_ERROR_P_MASK;
@@ -888,7 +899,7 @@
         env->cr[2] = addr;
     }
     env->error_code = error_code;
-    env->exception_index = EXCP0E_PAGE;
+    cs->exception_index = EXCP0E_PAGE;
     return 1;
 }
 
@@ -989,12 +1000,13 @@
 
 void hw_breakpoint_insert(CPUX86State *env, int index)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     int type = 0, err = 0;
 
     switch (hw_breakpoint_type(env->dr[7], index)) {
     case DR7_TYPE_BP_INST:
         if (hw_breakpoint_enabled(env->dr[7], index)) {
-            err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU,
+            err = cpu_breakpoint_insert(cs, env->dr[index], BP_CPU,
                                         &env->cpu_breakpoint[index]);
         }
         break;
@@ -1010,7 +1022,7 @@
     }
 
     if (type != 0) {
-        err = cpu_watchpoint_insert(env, env->dr[index],
+        err = cpu_watchpoint_insert(cs, env->dr[index],
                                     hw_breakpoint_len(env->dr[7], index),
                                     type, &env->cpu_watchpoint[index]);
     }
@@ -1022,17 +1034,21 @@
 
 void hw_breakpoint_remove(CPUX86State *env, int index)
 {
-    if (!env->cpu_breakpoint[index])
+    CPUState *cs;
+
+    if (!env->cpu_breakpoint[index]) {
         return;
+    }
+    cs = CPU(x86_env_get_cpu(env));
     switch (hw_breakpoint_type(env->dr[7], index)) {
     case DR7_TYPE_BP_INST:
         if (hw_breakpoint_enabled(env->dr[7], index)) {
-            cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]);
+            cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
         }
         break;
     case DR7_TYPE_DATA_WR:
     case DR7_TYPE_DATA_RW:
-        cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]);
+        cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
         break;
     case DR7_TYPE_IO_RW:
         /* No support for I/O watchpoints yet */
@@ -1084,19 +1100,20 @@
 
 void breakpoint_handler(CPUX86State *env)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     CPUBreakpoint *bp;
 
-    if (env->watchpoint_hit) {
-        if (env->watchpoint_hit->flags & BP_CPU) {
-            env->watchpoint_hit = NULL;
+    if (cs->watchpoint_hit) {
+        if (cs->watchpoint_hit->flags & BP_CPU) {
+            cs->watchpoint_hit = NULL;
             if (check_hw_breakpoints(env, false)) {
                 raise_exception(env, EXCP01_DB);
             } else {
-                cpu_resume_from_signal(env, NULL);
+                cpu_resume_from_signal(cs, NULL);
             }
         }
     } else {
-        QTAILQ_FOREACH(bp, &env->breakpoints, entry)
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == env->eip) {
                 if (bp->flags & BP_CPU) {
                     check_hw_breakpoints(env, true);
@@ -1104,6 +1121,7 @@
                 }
                 break;
             }
+        }
     }
 }
 
@@ -1250,13 +1268,14 @@
 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
 {
     X86CPU *cpu = x86_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
 
     if (kvm_enabled()) {
         env->tpr_access_type = access;
 
-        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TPR);
+        cpu_interrupt(cs, CPU_INTERRUPT_TPR);
     } else {
-        cpu_restore_state(env, env->mem_io_pc);
+        cpu_restore_state(cs, cs->mem_io_pc);
 
         apic_handle_tpr_access_report(cpu->apic_state, env->eip, access);
     }
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index e555040..7a295f6 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -2277,13 +2277,13 @@
                         break;
                     case 0x1:
                         ret = EXCP_DEBUG;
-                        env->watchpoint_hit = &hw_watchpoint;
+                        cs->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_WRITE;
                         break;
                     case 0x3:
                         ret = EXCP_DEBUG;
-                        env->watchpoint_hit = &hw_watchpoint;
+                        cs->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_ACCESS;
                         break;
@@ -2291,11 +2291,11 @@
                 }
             }
         }
-    } else if (kvm_find_sw_breakpoint(CPU(cpu), arch_info->pc)) {
+    } else if (kvm_find_sw_breakpoint(cs, arch_info->pc)) {
         ret = EXCP_DEBUG;
     }
     if (ret == 0) {
-        cpu_synchronize_state(CPU(cpu));
+        cpu_synchronize_state(cs);
         assert(env->exception_injected == -1);
 
         /* pass to guest */
diff --git a/target-i386/machine.c b/target-i386/machine.c
index d548c05..24bc373 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -290,6 +290,7 @@
 static int cpu_post_load(void *opaque, int version_id)
 {
     X86CPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
     CPUX86State *env = &cpu->env;
     int i;
 
@@ -319,12 +320,12 @@
         env->fptags[i] = (env->fptag_vmstate >> i) & 1;
     }
 
-    cpu_breakpoint_remove_all(env, BP_CPU);
-    cpu_watchpoint_remove_all(env, BP_CPU);
+    cpu_breakpoint_remove_all(cs, BP_CPU);
+    cpu_watchpoint_remove_all(cs, BP_CPU);
     for (i = 0; i < DR7_MAX_BP; i++) {
         hw_breakpoint_insert(env, i);
     }
-    tlb_flush(env, 1);
+    tlb_flush(cs, 1);
 
     return 0;
 }
diff --git a/target-i386/mem_helper.c b/target-i386/mem_helper.c
index 319a219..b3b811b 100644
--- a/target-i386/mem_helper.c
+++ b/target-i386/mem_helper.c
@@ -129,21 +129,25 @@
 
 #if !defined(CONFIG_USER_ONLY)
 /* try to fill the TLB and return an exception if error. If retaddr is
-   NULL, it means that the function was called in C code (i.e. not
-   from generated code or from helper.c) */
+ * NULL, it means that the function was called in C code (i.e. not
+ * from generated code or from helper.c)
+ */
 /* XXX: fix it to restore all registers */
-void tlb_fill(CPUX86State *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = x86_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (ret) {
+        X86CPU *cpu = X86_CPU(cs);
+        CPUX86State *env = &cpu->env;
+
         if (retaddr) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        raise_exception_err(env, env->exception_index, env->error_code);
+        raise_exception_err(env, cs->exception_index, env->error_code);
     }
 }
 #endif
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index 47f6a2f..1e2da1e 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -221,8 +221,10 @@
 
 void helper_invlpg(CPUX86State *env, target_ulong addr)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
+
     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0);
-    tlb_flush_page(env, addr);
+    tlb_flush_page(CPU(cpu), addr);
 }
 
 void helper_rdtsc(CPUX86State *env)
@@ -568,11 +570,11 @@
 
 static void do_pause(X86CPU *cpu)
 {
-    CPUX86State *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
     /* Just let another CPU run.  */
-    env->exception_index = EXCP_INTERRUPT;
-    cpu_loop_exit(env);
+    cs->exception_index = EXCP_INTERRUPT;
+    cpu_loop_exit(cs);
 }
 
 static void do_hlt(X86CPU *cpu)
@@ -582,8 +584,8 @@
 
     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
     cs->halted = 1;
-    env->exception_index = EXCP_HLT;
-    cpu_loop_exit(env);
+    cs->exception_index = EXCP_HLT;
+    cpu_loop_exit(cs);
 }
 
 void helper_hlt(CPUX86State *env, int next_eip_addend)
@@ -638,6 +640,8 @@
 
 void helper_debug(CPUX86State *env)
 {
-    env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
+    cs->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(cs);
 }
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 959212b..8c3f92c 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -95,6 +95,7 @@
 static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr,
                                        uint32_t *esp_ptr, int dpl)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     int type, index, shift;
 
 #if 0
@@ -112,11 +113,11 @@
 #endif
 
     if (!(env->tr.flags & DESC_P_MASK)) {
-        cpu_abort(env, "invalid tss");
+        cpu_abort(CPU(cpu), "invalid tss");
     }
     type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
     if ((type & 7) != 1) {
-        cpu_abort(env, "invalid tss type");
+        cpu_abort(CPU(cpu), "invalid tss type");
     }
     shift = type >> 3;
     index = (dpl * 4 + 2) << shift;
@@ -782,6 +783,7 @@
 
 static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     int index;
 
 #if 0
@@ -790,7 +792,7 @@
 #endif
 
     if (!(env->tr.flags & DESC_P_MASK)) {
-        cpu_abort(env, "invalid tss");
+        cpu_abort(CPU(cpu), "invalid tss");
     }
     index = 8 * level + 4;
     if ((index + 7) > env->tr.limit) {
@@ -935,9 +937,11 @@
 #if defined(CONFIG_USER_ONLY)
 void helper_syscall(CPUX86State *env, int next_eip_addend)
 {
-    env->exception_index = EXCP_SYSCALL;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
+    cs->exception_index = EXCP_SYSCALL;
     env->exception_next_eip = env->eip + next_eip_addend;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 #else
 void helper_syscall(CPUX86State *env, int next_eip_addend)
@@ -1131,7 +1135,7 @@
 static void handle_even_inj(CPUX86State *env, int intno, int is_int,
                             int error_code, int is_hw, int rm)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     uint32_t event_inj = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
                                                           control.event_inj));
 
@@ -1248,7 +1252,7 @@
     /* if user mode only, we simulate a fake exception
        which will be handled outside the cpu execution
        loop */
-    do_interrupt_user(env, env->exception_index,
+    do_interrupt_user(env, cs->exception_index,
                       env->exception_is_int,
                       env->error_code,
                       env->exception_next_eip);
@@ -1258,7 +1262,7 @@
     /* simulate a real cpu exception. On i386, it can
        trigger new exceptions, but we do not handle
        double or triple faults yet. */
-    do_interrupt_all(cpu, env->exception_index,
+    do_interrupt_all(cpu, cs->exception_index,
                      env->exception_is_int,
                      env->error_code,
                      env->exception_next_eip, 0);
diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c
index 71c64b2..35901c9 100644
--- a/target-i386/smm_helper.c
+++ b/target-i386/smm_helper.c
@@ -181,8 +181,8 @@
 
 void helper_rsm(CPUX86State *env)
 {
-    CPUState *cs = ENV_GET_CPU(env);
     X86CPU *cpu = x86_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
     target_ulong sm_state;
     int i, offset;
     uint32_t val;
diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c
index b38d450..aa17ecd 100644
--- a/target-i386/svm_helper.c
+++ b/target-i386/svm_helper.c
@@ -88,7 +88,8 @@
 static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
                                 const SegmentCache *sc)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
     stw_phys(cs->as, addr + offsetof(struct vmcb_seg, selector),
              sc->selector);
     stq_phys(cs->as, addr + offsetof(struct vmcb_seg, base),
@@ -102,7 +103,7 @@
 static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
                                 SegmentCache *sc)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     unsigned int flags;
 
     sc->selector = lduw_phys(cs->as,
@@ -125,7 +126,7 @@
 
 void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     target_ulong addr;
     uint32_t event_inj;
     uint32_t int_ctl;
@@ -293,7 +294,7 @@
         break;
     case TLB_CONTROL_FLUSH_ALL_ASID:
         /* FIXME: this is not 100% correct but should work for now */
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
         break;
     }
 
@@ -319,7 +320,7 @@
         /* FIXME: need to implement valid_err */
         switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
         case SVM_EVTINJ_TYPE_INTR:
-            env->exception_index = vector;
+            cs->exception_index = vector;
             env->error_code = event_inj_err;
             env->exception_is_int = 0;
             env->exception_next_eip = -1;
@@ -328,31 +329,31 @@
             do_interrupt_x86_hardirq(env, vector, 1);
             break;
         case SVM_EVTINJ_TYPE_NMI:
-            env->exception_index = EXCP02_NMI;
+            cs->exception_index = EXCP02_NMI;
             env->error_code = event_inj_err;
             env->exception_is_int = 0;
             env->exception_next_eip = env->eip;
             qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
-            cpu_loop_exit(env);
+            cpu_loop_exit(cs);
             break;
         case SVM_EVTINJ_TYPE_EXEPT:
-            env->exception_index = vector;
+            cs->exception_index = vector;
             env->error_code = event_inj_err;
             env->exception_is_int = 0;
             env->exception_next_eip = -1;
             qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
-            cpu_loop_exit(env);
+            cpu_loop_exit(cs);
             break;
         case SVM_EVTINJ_TYPE_SOFT:
-            env->exception_index = vector;
+            cs->exception_index = vector;
             env->error_code = event_inj_err;
             env->exception_is_int = 1;
             env->exception_next_eip = env->eip;
             qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
-            cpu_loop_exit(env);
+            cpu_loop_exit(cs);
             break;
         }
-        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index,
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
                       env->error_code);
     }
 }
@@ -365,7 +366,7 @@
 
 void helper_vmload(CPUX86State *env, int aflag)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     target_ulong addr;
 
     cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
@@ -405,7 +406,7 @@
 
 void helper_vmsave(CPUX86State *env, int aflag)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     target_ulong addr;
 
     cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
@@ -468,6 +469,7 @@
 
 void helper_invlpga(CPUX86State *env, int aflag)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     target_ulong addr;
 
     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
@@ -480,13 +482,13 @@
 
     /* XXX: could use the ASID to see if it is needed to do the
        flush */
-    tlb_flush_page(env, addr);
+    tlb_flush_page(CPU(cpu), addr);
 }
 
 void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
                                       uint64_t param)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
 
     if (likely(!(env->hflags & HF_SVMI_MASK))) {
         return;
@@ -568,7 +570,8 @@
 void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
                          uint32_t next_eip_addend)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
     if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
         /* FIXME: this should be read in at vmrun (faster this way?) */
         uint64_t addr = ldq_phys(cs->as, env->vm_vmcb +
@@ -766,11 +769,11 @@
        #GP fault is delivered inside the host. */
 
     /* remove any pending exception */
-    env->exception_index = -1;
+    cs->exception_index = -1;
     env->error_code = 0;
     env->old_exception = -1;
 
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 707ebd5..02625e3 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7965,8 +7965,8 @@
 
     gen_tb_start();
     for(;;) {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == pc_ptr &&
                     !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
                     gen_debug(dc, pc_ptr - dc->cs_base);
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 7e716fb..c5c20d7 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -110,6 +110,11 @@
     env->cfg = cfg;
 }
 
+static bool lm32_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
 /* CPUClass::reset() */
 static void lm32_cpu_reset(CPUState *s)
 {
@@ -120,10 +125,10 @@
     lcc->parent_reset(s);
 
     /* reset cpu state */
-    memset(env, 0, offsetof(CPULM32State, breakpoints));
+    memset(env, 0, offsetof(CPULM32State, eba));
 
     lm32_cpu_init_cfg_reg(cpu);
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 }
 
 static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)
@@ -255,12 +260,15 @@
     cc->reset = lm32_cpu_reset;
 
     cc->class_by_name = lm32_cpu_class_by_name;
+    cc->has_work = lm32_cpu_has_work;
     cc->do_interrupt = lm32_cpu_do_interrupt;
     cc->dump_state = lm32_cpu_dump_state;
     cc->set_pc = lm32_cpu_set_pc;
     cc->gdb_read_register = lm32_cpu_gdb_read_register;
     cc->gdb_write_register = lm32_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = lm32_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
     cc->vmsd = &vmstate_lm32_cpu;
 #endif
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index 18cf348..24bde78 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -166,11 +166,12 @@
     uint32_t bp[4];     /* breakpoints */
     uint32_t wp[4];     /* watchpoints */
 
-    CPUBreakpoint * cpu_breakpoint[4];
-    CPUWatchpoint * cpu_watchpoint[4];
+    struct CPUBreakpoint *cpu_breakpoint[4];
+    struct CPUWatchpoint *cpu_watchpoint[4];
 
     CPU_COMMON
 
+    /* Fields from here on are preserved across CPU reset. */
     uint32_t eba;       /* exception base address */
     uint32_t deba;      /* debug exception base address */
 
@@ -231,9 +232,8 @@
 #define cpu_gen_code cpu_lm32_gen_code
 #define cpu_signal_handler cpu_lm32_signal_handler
 
-int cpu_lm32_handle_mmu_fault(CPULM32State *env, target_ulong address, int rw,
+int lm32_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
                               int mmu_idx);
-#define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault
 
 #include "exec/cpu-all.h"
 
@@ -245,11 +245,6 @@
     *flags = 0;
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request & CPU_INTERRUPT_HARD;
-}
-
 #include "exec/exec-all.h"
 
 #endif
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index eecb9f6..783aa16 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -20,18 +20,20 @@
 #include "cpu.h"
 #include "qemu/host-utils.h"
 
-int cpu_lm32_handle_mmu_fault(CPULM32State *env, target_ulong address, int rw,
+int lm32_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                               int mmu_idx)
 {
+    LM32CPU *cpu = LM32_CPU(cs);
+    CPULM32State *env = &cpu->env;
     int prot;
 
     address &= TARGET_PAGE_MASK;
     prot = PAGE_BITS;
     if (env->flags & LM32_FLAG_IGNORE_MSB) {
-        tlb_set_page(env, address, address & 0x7fffffff, prot, mmu_idx,
-                TARGET_PAGE_SIZE);
+        tlb_set_page(cs, address, address & 0x7fffffff, prot, mmu_idx,
+                     TARGET_PAGE_SIZE);
     } else {
-        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+        tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
     }
 
     return 0;
@@ -51,22 +53,28 @@
 
 void lm32_breakpoint_insert(CPULM32State *env, int idx, target_ulong address)
 {
-    cpu_breakpoint_insert(env, address, BP_CPU, &env->cpu_breakpoint[idx]);
+    LM32CPU *cpu = lm32_env_get_cpu(env);
+
+    cpu_breakpoint_insert(CPU(cpu), address, BP_CPU,
+                          &env->cpu_breakpoint[idx]);
 }
 
 void lm32_breakpoint_remove(CPULM32State *env, int idx)
 {
+    LM32CPU *cpu = lm32_env_get_cpu(env);
+
     if (!env->cpu_breakpoint[idx]) {
         return;
     }
 
-    cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[idx]);
+    cpu_breakpoint_remove_by_ref(CPU(cpu), env->cpu_breakpoint[idx]);
     env->cpu_breakpoint[idx] = NULL;
 }
 
 void lm32_watchpoint_insert(CPULM32State *env, int idx, target_ulong address,
                             lm32_wp_t wp_type)
 {
+    LM32CPU *cpu = lm32_env_get_cpu(env);
     int flags = 0;
 
     switch (wp_type) {
@@ -85,18 +93,20 @@
     }
 
     if (flags != 0) {
-        cpu_watchpoint_insert(env, address, 1, flags,
+        cpu_watchpoint_insert(CPU(cpu), address, 1, flags,
                 &env->cpu_watchpoint[idx]);
     }
 }
 
 void lm32_watchpoint_remove(CPULM32State *env, int idx)
 {
+    LM32CPU *cpu = lm32_env_get_cpu(env);
+
     if (!env->cpu_watchpoint[idx]) {
         return;
     }
 
-    cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[idx]);
+    cpu_watchpoint_remove_by_ref(CPU(cpu), env->cpu_watchpoint[idx]);
     env->cpu_watchpoint[idx] = NULL;
 }
 
@@ -116,19 +126,20 @@
 
 void lm32_debug_excp_handler(CPULM32State *env)
 {
+    CPUState *cs = CPU(lm32_env_get_cpu(env));
     CPUBreakpoint *bp;
 
-    if (env->watchpoint_hit) {
-        if (env->watchpoint_hit->flags & BP_CPU) {
-            env->watchpoint_hit = NULL;
+    if (cs->watchpoint_hit) {
+        if (cs->watchpoint_hit->flags & BP_CPU) {
+            cs->watchpoint_hit = NULL;
             if (check_watchpoints(env)) {
                 raise_exception(env, EXCP_WATCHPOINT);
             } else {
-                cpu_resume_from_signal(env, NULL);
+                cpu_resume_from_signal(cs, NULL);
             }
         }
     } else {
-        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == env->pc) {
                 if (bp->flags & BP_CPU) {
                     raise_exception(env, EXCP_BREAKPOINT);
@@ -145,9 +156,9 @@
     CPULM32State *env = &cpu->env;
 
     qemu_log_mask(CPU_LOG_INT,
-            "exception at pc=%x type=%x\n", env->pc, env->exception_index);
+            "exception at pc=%x type=%x\n", env->pc, cs->exception_index);
 
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXCP_INSN_BUS_ERROR:
     case EXCP_DATA_BUS_ERROR:
     case EXCP_DIVIDE_BY_ZERO:
@@ -158,9 +169,9 @@
         env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
         env->ie &= ~IE_IE;
         if (env->dc & DC_RE) {
-            env->pc = env->deba + (env->exception_index * 32);
+            env->pc = env->deba + (cs->exception_index * 32);
         } else {
-            env->pc = env->eba + (env->exception_index * 32);
+            env->pc = env->eba + (cs->exception_index * 32);
         }
         log_cpu_state_mask(CPU_LOG_INT, cs, 0);
         break;
@@ -170,30 +181,19 @@
         env->regs[R_BA] = env->pc;
         env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
         env->ie &= ~IE_IE;
-        env->pc = env->deba + (env->exception_index * 32);
+        env->pc = env->deba + (cs->exception_index * 32);
         log_cpu_state_mask(CPU_LOG_INT, cs, 0);
         break;
     default:
-        cpu_abort(env, "unhandled exception type=%d\n",
-                  env->exception_index);
+        cpu_abort(cs, "unhandled exception type=%d\n",
+                  cs->exception_index);
         break;
     }
 }
 
 LM32CPU *cpu_lm32_init(const char *cpu_model)
 {
-    LM32CPU *cpu;
-    ObjectClass *oc;
-
-    oc = cpu_class_by_name(TYPE_LM32_CPU, cpu_model);
-    if (oc == NULL) {
-        return NULL;
-    }
-    cpu = LM32_CPU(object_new(object_class_get_name(oc)));
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return cpu;
+    return LM32_CPU(cpu_generic_init(TYPE_LM32_CPU, cpu_model));
 }
 
 /* Some soc ignores the MSB on the address bus. Thus creating a shadow memory
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index 7189cb5..2f36b7b 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -25,8 +25,10 @@
 
 void raise_exception(CPULM32State *env, int index)
 {
-    env->exception_index = index;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(lm32_env_get_cpu(env));
+
+    cs->exception_index = index;
+    cpu_loop_exit(cs);
 }
 
 void HELPER(raise_exception)(CPULM32State *env, uint32_t index)
@@ -39,8 +41,8 @@
     CPUState *cs = CPU(lm32_env_get_cpu(env));
 
     cs->halted = 1;
-    env->exception_index = EXCP_HLT;
-    cpu_loop_exit(env);
+    cs->exception_index = EXCP_HLT;
+    cpu_loop_exit(cs);
 }
 
 void HELPER(ill)(CPULM32State *env)
@@ -148,20 +150,21 @@
 }
 
 /* Try to fill the TLB and return an exception if error. If retaddr is
-   NULL, it means that the function was called in C code (i.e. not
-   from generated code or from helper.c) */
-void tlb_fill(CPULM32State *env, target_ulong addr, int is_write, int mmu_idx,
+ * NULL, it means that the function was called in C code (i.e. not
+ * from generated code or from helper.c)
+ */
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_lm32_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = lm32_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 #endif
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index 80bffc7..c8abd1f 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -1037,10 +1037,11 @@
 
 static void check_breakpoint(CPULM32State *env, DisasContext *dc)
 {
+    CPUState *cs = CPU(lm32_env_get_cpu(env));
     CPUBreakpoint *bp;
 
-    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+    if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == dc->pc) {
                 tcg_gen_movi_tl(cpu_pc, dc->pc);
                 t_gen_raise_exception(dc, EXCP_DEBUG);
diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c
index 008d8db..c9cff19 100644
--- a/target-m68k/cpu.c
+++ b/target-m68k/cpu.c
@@ -30,6 +30,11 @@
     cpu->env.pc = value;
 }
 
+static bool m68k_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
 static void m68k_set_feature(CPUM68KState *env, int feature)
 {
     env->features |= (1u << feature);
@@ -44,7 +49,7 @@
 
     mcc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUM68KState, breakpoints));
+    memset(env, 0, offsetof(CPUM68KState, features));
 #if !defined(CONFIG_USER_ONLY)
     env->sr = 0x2700;
 #endif
@@ -53,7 +58,7 @@
     env->cc_op = CC_OP_FLAGS;
     /* TODO: We should set PC from the interrupt vector.  */
     env->pc = 0;
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 }
 
 /* CPU models */
@@ -189,12 +194,15 @@
     cc->reset = m68k_cpu_reset;
 
     cc->class_by_name = m68k_cpu_class_by_name;
+    cc->has_work = m68k_cpu_has_work;
     cc->do_interrupt = m68k_cpu_do_interrupt;
     cc->dump_state = m68k_cpu_dump_state;
     cc->set_pc = m68k_cpu_set_pc;
     cc->gdb_read_register = m68k_cpu_gdb_read_register;
     cc->gdb_write_register = m68k_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = m68k_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
 #endif
     dc->vmsd = &vmstate_m68k_cpu;
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index cfd6846..6e4001d 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -110,6 +110,7 @@
 
     CPU_COMMON
 
+    /* Fields from here on are preserved across CPU reset. */
     uint32_t features;
 } CPUM68KState;
 
@@ -237,9 +238,8 @@
     return (env->sr & SR_S) == 0 ? 1 : 0;
 }
 
-int cpu_m68k_handle_mmu_fault(CPUM68KState *env, target_ulong address, int rw,
+int m68k_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
                               int mmu_idx);
-#define cpu_handle_mmu_fault cpu_m68k_handle_mmu_fault
 
 #include "exec/cpu-all.h"
 
@@ -253,11 +253,6 @@
             | ((env->macsr >> 4) & 0xf);        /* Bits 0-3 */
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request & CPU_INTERRUPT_HARD;
-}
-
 #include "exec/exec-all.h"
 
 #endif
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index a364eb1..077b653 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -132,6 +132,7 @@
 
 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
 {
+    M68kCPU *cpu = m68k_env_get_cpu(env);
     int flags;
     uint32_t src;
     uint32_t dest;
@@ -204,7 +205,7 @@
             flags |= CCF_C;
         break;
     default:
-        cpu_abort(env, "Bad CC_OP %d", cc_op);
+        cpu_abort(CPU(cpu), "Bad CC_OP %d", cc_op);
     }
     env->cc_op = CC_OP_FLAGS;
     env->cc_dest = flags;
@@ -212,6 +213,8 @@
 
 void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
 {
+    M68kCPU *cpu = m68k_env_get_cpu(env);
+
     switch (reg) {
     case 0x02: /* CACR */
         env->cacr = val;
@@ -225,7 +228,7 @@
         break;
     /* TODO: Implement control registers.  */
     default:
-        cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
+        cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
                   reg, val);
     }
 }
@@ -277,11 +280,13 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw,
-                               int mmu_idx)
+int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                              int mmu_idx)
 {
-    env->exception_index = EXCP_ACCESS;
-    env->mmu.ar = address;
+    M68kCPU *cpu = M68K_CPU(cs);
+
+    cs->exception_index = EXCP_ACCESS;
+    cpu->env.mmu.ar = address;
     return 1;
 }
 
@@ -295,14 +300,14 @@
     return addr;
 }
 
-int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw,
-                               int mmu_idx)
+int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                              int mmu_idx)
 {
     int prot;
 
     address &= TARGET_PAGE_MASK;
     prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-    tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+    tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
     return 0;
 }
 
diff --git a/target-m68k/m68k-semi.c b/target-m68k/m68k-semi.c
index 94c4983..9dffe8d 100644
--- a/target-m68k/m68k-semi.c
+++ b/target-m68k/m68k-semi.c
@@ -428,7 +428,8 @@
     case HOSTED_INIT_SIM:
 #if defined(CONFIG_USER_ONLY)
         {
-        TaskState *ts = env->opaque;
+        CPUState *cs = CPU(m68k_env_get_cpu(env));
+        TaskState *ts = cs->opaque;
         /* Allocate the heap using sbrk.  */
         if (!ts->heap_limit) {
             abi_ulong ret;
@@ -460,7 +461,7 @@
 #endif
         return;
     default:
-        cpu_abort(env, "Unsupported semihosting syscall %d\n", nr);
+        cpu_abort(CPU(m68k_env_get_cpu(env)), "Unsupported semihosting syscall %d\n", nr);
         result = 0;
     }
 failed:
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index bbbfd7f..06302b1 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -23,10 +23,7 @@
 
 void m68k_cpu_do_interrupt(CPUState *cs)
 {
-    M68kCPU *cpu = M68K_CPU(cs);
-    CPUM68KState *env = &cpu->env;
-
-    env->exception_index = -1;
+    cs->exception_index = -1;
 }
 
 void do_interrupt_m68k_hardirq(CPUM68KState *env)
@@ -56,18 +53,18 @@
 /* Try to fill the TLB and return an exception if error. If retaddr is
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
-void tlb_fill(CPUM68KState *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = m68k_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 
@@ -87,7 +84,7 @@
 
 static void do_interrupt_all(CPUM68KState *env, int is_hw)
 {
-    CPUState *cs;
+    CPUState *cs = CPU(m68k_env_get_cpu(env));
     uint32_t sp;
     uint32_t fmt;
     uint32_t retaddr;
@@ -97,7 +94,7 @@
     retaddr = env->pc;
 
     if (!is_hw) {
-        switch (env->exception_index) {
+        switch (cs->exception_index) {
         case EXCP_RTE:
             /* Return from an exception.  */
             do_rte(env);
@@ -112,20 +109,19 @@
                 do_m68k_semihosting(env, env->dregs[0]);
                 return;
             }
-            cs = CPU(m68k_env_get_cpu(env));
             cs->halted = 1;
-            env->exception_index = EXCP_HLT;
-            cpu_loop_exit(env);
+            cs->exception_index = EXCP_HLT;
+            cpu_loop_exit(cs);
             return;
         }
-        if (env->exception_index >= EXCP_TRAP0
-            && env->exception_index <= EXCP_TRAP15) {
+        if (cs->exception_index >= EXCP_TRAP0
+            && cs->exception_index <= EXCP_TRAP15) {
             /* Move the PC after the trap instruction.  */
             retaddr += 2;
         }
     }
 
-    vector = env->exception_index << 2;
+    vector = cs->exception_index << 2;
 
     sp = env->aregs[7];
 
@@ -168,8 +164,10 @@
 
 static void raise_exception(CPUM68KState *env, int tt)
 {
-    env->exception_index = tt;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(m68k_env_get_cpu(env));
+
+    cs->exception_index = tt;
+    cpu_loop_exit(cs);
 }
 
 void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt)
diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def
index 4235b02..204663e 100644
--- a/target-m68k/qregs.def
+++ b/target-m68k/qregs.def
@@ -7,6 +7,5 @@
 DEFO32(CC_X, cc_x)
 DEFO32(DIV1, div1)
 DEFO32(DIV2, div2)
-DEFO32(EXCEPTION, exception_index)
 DEFO32(MACSR, macsr)
 DEFO32(MAC_MASK, mac_mask)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index f54b94a..cd66289 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -43,6 +43,7 @@
 #undef DEFF64
 
 static TCGv_i32 cpu_halted;
+static TCGv_i32 cpu_exception_index;
 
 static TCGv_ptr cpu_env;
 
@@ -81,6 +82,10 @@
     cpu_halted = tcg_global_mem_new_i32(TCG_AREG0,
                                         -offsetof(M68kCPU, env) +
                                         offsetof(CPUState, halted), "HALTED");
+    cpu_exception_index = tcg_global_mem_new_i32(TCG_AREG0,
+                                                 -offsetof(M68kCPU, env) +
+                                                 offsetof(CPUState, exception_index),
+                                                 "EXCEPTION");
 
     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
 
@@ -110,14 +115,6 @@
     store_dummy = tcg_global_mem_new(TCG_AREG0, -8, "NULL");
 }
 
-static inline void qemu_assert(int cond, const char *msg)
-{
-    if (!cond) {
-        fprintf (stderr, "badness: %s\n", msg);
-        abort();
-    }
-}
-
 /* internal defines */
 typedef struct DisasContext {
     CPUM68KState *env;
@@ -199,7 +196,7 @@
         tcg_gen_qemu_ld32u(tmp, addr, index);
         break;
     default:
-        qemu_assert(0, "bad load size");
+        g_assert_not_reached();
     }
     gen_throws_exception = gen_last_qop;
     return tmp;
@@ -233,7 +230,7 @@
         tcg_gen_qemu_st32(val, addr, index);
         break;
     default:
-        qemu_assert(0, "bad store size");
+        g_assert_not_reached();
     }
     gen_throws_exception = gen_last_qop;
 }
@@ -437,8 +434,7 @@
     case OS_SINGLE: return 4;
     case OS_DOUBLE: return 8;
     default:
-        qemu_assert(0, "bad operand size");
-        return 0;
+        g_assert_not_reached();
     }
 }
 
@@ -465,8 +461,7 @@
         tcg_gen_mov_i32(reg, val);
         break;
     default:
-        qemu_assert(0, "Bad operand size");
-        break;
+        g_assert_not_reached();
     }
 }
 
@@ -495,7 +490,7 @@
         tmp = val;
         break;
     default:
-        qemu_assert(0, "Bad operand size");
+        g_assert_not_reached();
     }
     return tmp;
 }
@@ -669,7 +664,7 @@
                 offset = read_im32(env, s);
                 break;
             default:
-                qemu_assert(0, "Bad immediate operand");
+                g_assert_not_reached();
             }
             return tcg_const_i32(offset);
         default:
@@ -886,8 +881,10 @@
 
 DISAS_INSN(undef)
 {
+    M68kCPU *cpu = m68k_env_get_cpu(env);
+
     gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED);
-    cpu_abort(env, "Illegal instruction: %04x @ %08x", insn, s->pc - 2);
+    cpu_abort(CPU(cpu), "Illegal instruction: %04x @ %08x", insn, s->pc - 2);
 }
 
 DISAS_INSN(mulw)
@@ -2087,12 +2084,14 @@
 
 DISAS_INSN(wdebug)
 {
+    M68kCPU *cpu = m68k_env_get_cpu(env);
+
     if (IS_USER(s)) {
         gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
         return;
     }
     /* TODO: Implement wdebug.  */
-    qemu_assert(0, "WDEBUG not implemented");
+    cpu_abort(CPU(cpu), "WDEBUG not implemented");
 }
 
 DISAS_INSN(trap)
@@ -2466,14 +2465,18 @@
 
 DISAS_INSN(frestore)
 {
+    M68kCPU *cpu = m68k_env_get_cpu(env);
+
     /* TODO: Implement frestore.  */
-    qemu_assert(0, "FRESTORE not implemented");
+    cpu_abort(CPU(cpu), "FRESTORE not implemented");
 }
 
 DISAS_INSN(fsave)
 {
+    M68kCPU *cpu = m68k_env_get_cpu(env);
+
     /* TODO: Implement fsave.  */
-    qemu_assert(0, "FSAVE not implemented");
+    cpu_abort(CPU(cpu), "FSAVE not implemented");
 }
 
 static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
@@ -3008,8 +3011,8 @@
     do {
         pc_offset = dc->pc - pc_start;
         gen_throws_exception = NULL;
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
                     gen_exception(dc, dc->pc, EXCP_DEBUG);
                     dc->is_jmp = DISAS_JUMP;
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index f108c0b..8e04811 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -34,6 +34,11 @@
     cpu->env.sregs[SR_PC] = value;
 }
 
+static bool mb_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+}
+
 #ifndef CONFIG_USER_ONLY
 static void microblaze_cpu_set_irq(void *opaque, int irq, int level)
 {
@@ -58,9 +63,9 @@
 
     mcc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUMBState, breakpoints));
+    memset(env, 0, sizeof(CPUMBState));
     env->res_addr = RES_ADDR_NONE;
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 
     /* Disable stack protector.  */
     env->shr = ~0;
@@ -160,12 +165,15 @@
     mcc->parent_reset = cc->reset;
     cc->reset = mb_cpu_reset;
 
+    cc->has_work = mb_cpu_has_work;
     cc->do_interrupt = mb_cpu_do_interrupt;
     cc->dump_state = mb_cpu_dump_state;
     cc->set_pc = mb_cpu_set_pc;
     cc->gdb_read_register = mb_cpu_gdb_read_register;
     cc->gdb_write_register = mb_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = mb_cpu_handle_mmu_fault;
+#else
     cc->do_unassigned_access = mb_cpu_unassigned_access;
     cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
 #endif
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 1df014e..6ccd060 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -332,9 +332,8 @@
         return MMU_KERNEL_IDX;
 }
 
-int cpu_mb_handle_mmu_fault(CPUMBState *env, target_ulong address, int rw,
+int mb_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
                             int mmu_idx);
-#define cpu_handle_mmu_fault cpu_mb_handle_mmu_fault
 
 static inline int cpu_interrupts_enabled(CPUMBState *env)
 {
@@ -363,11 +362,6 @@
                               unsigned size);
 #endif
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
-}
-
 #include "exec/exec-all.h"
 
 #endif
diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c
index 4fa9ce9..59c9ad5 100644
--- a/target-microblaze/helper.c
+++ b/target-microblaze/helper.c
@@ -31,26 +31,26 @@
     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
     CPUMBState *env = &cpu->env;
 
-    env->exception_index = -1;
+    cs->exception_index = -1;
     env->res_addr = RES_ADDR_NONE;
     env->regs[14] = env->sregs[SR_PC];
 }
 
-int cpu_mb_handle_mmu_fault(CPUMBState * env, target_ulong address, int rw,
+int mb_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                             int mmu_idx)
 {
-    MicroBlazeCPU *cpu = mb_env_get_cpu(env);
-
-    env->exception_index = 0xaa;
-    cpu_dump_state(CPU(cpu), stderr, fprintf, 0);
+    cs->exception_index = 0xaa;
+    cpu_dump_state(cs, stderr, fprintf, 0);
     return 1;
 }
 
 #else /* !CONFIG_USER_ONLY */
 
-int cpu_mb_handle_mmu_fault (CPUMBState *env, target_ulong address, int rw,
-                             int mmu_idx)
+int mb_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                            int mmu_idx)
 {
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUMBState *env = &cpu->env;
     unsigned int hit;
     unsigned int mmu_available;
     int r = 1;
@@ -77,7 +77,7 @@
 
             DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n",
                      mmu_idx, vaddr, paddr, lu.prot));
-            tlb_set_page(env, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE);
+            tlb_set_page(cs, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE);
             r = 0;
         } else {
             env->sregs[SR_EAR] = address;
@@ -97,18 +97,18 @@
                     break;
             }
 
-            if (env->exception_index == EXCP_MMU) {
-                cpu_abort(env, "recursive faults\n");
+            if (cs->exception_index == EXCP_MMU) {
+                cpu_abort(cs, "recursive faults\n");
             }
 
             /* TLB miss.  */
-            env->exception_index = EXCP_MMU;
+            cs->exception_index = EXCP_MMU;
         }
     } else {
         /* MMU disabled or not available.  */
         address &= TARGET_PAGE_MASK;
         prot = PAGE_BITS;
-        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+        tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
         r = 0;
     }
     return r;
@@ -125,7 +125,7 @@
     assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
 /*    assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions.  */
     env->res_addr = RES_ADDR_NONE;
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
         case EXCP_HW_EXCP:
             if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) {
                 qemu_log("Exception raised on system without exceptions!\n");
@@ -251,7 +251,7 @@
             env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
             env->sregs[SR_MSR] |= t;
             env->sregs[SR_MSR] |= MSR_BIP;
-            if (env->exception_index == EXCP_HW_BREAK) {
+            if (cs->exception_index == EXCP_HW_BREAK) {
                 env->regs[16] = env->sregs[SR_PC];
                 env->sregs[SR_MSR] |= MSR_BIP;
                 env->sregs[SR_PC] = cpu->base_vectors + 0x18;
@@ -259,8 +259,8 @@
                 env->sregs[SR_PC] = env->btarget;
             break;
         default:
-            cpu_abort(env, "unhandled exception type=%d\n",
-                      env->exception_index);
+            cpu_abort(cs, "unhandled exception type=%d\n",
+                      cs->exception_index);
             break;
     }
 }
diff --git a/target-microblaze/mmu.c b/target-microblaze/mmu.c
index 73bf805..728da13 100644
--- a/target-microblaze/mmu.c
+++ b/target-microblaze/mmu.c
@@ -34,6 +34,7 @@
 
 static void mmu_flush_idx(CPUMBState *env, unsigned int idx)
 {
+    CPUState *cs = CPU(mb_env_get_cpu(env));
     struct microblaze_mmu *mmu = &env->mmu;
     unsigned int tlb_size;
     uint32_t tlb_tag, end, t;
@@ -47,7 +48,7 @@
     end = tlb_tag + tlb_size;
 
     while (tlb_tag < end) {
-        tlb_flush_page(env, tlb_tag);
+        tlb_flush_page(cs, tlb_tag);
         tlb_tag += TARGET_PAGE_SIZE;
     }
 }
@@ -218,6 +219,7 @@
 
 void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
 {
+    MicroBlazeCPU *cpu = mb_env_get_cpu(env);
     unsigned int i;
     D(qemu_log("%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]));
 
@@ -251,7 +253,7 @@
             /* Changes to the zone protection reg flush the QEMU TLB.
                Fortunately, these are very uncommon.  */
             if (v != env->mmu.regs[rn]) {
-                tlb_flush(env, 1);
+                tlb_flush(CPU(cpu), 1);
             }
             env->mmu.regs[rn] = v;
             break;
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index 14baa84..f8fb7f9 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -39,20 +39,21 @@
 #include "exec/softmmu_template.h"
 
 /* Try to fill the TLB and return an exception if error. If retaddr is
-   NULL, it means that the function was called in C code (i.e. not
-   from generated code or from helper.c) */
-void tlb_fill(CPUMBState *env, target_ulong addr, int is_write, int mmu_idx,
+ * NULL, it means that the function was called in C code (i.e. not
+ * from generated code or from helper.c)
+ */
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = mb_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 #endif
@@ -94,8 +95,10 @@
 
 void helper_raise_exception(CPUMBState *env, uint32_t index)
 {
-    env->exception_index = index;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(mb_env_get_cpu(env));
+
+    cs->exception_index = index;
+    cpu_loop_exit(cs);
 }
 
 void helper_debug(CPUMBState *env)
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 270138c..782a489 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -56,7 +56,7 @@
 
 /* This is the state at translation time.  */
 typedef struct DisasContext {
-    CPUMBState *env;
+    MicroBlazeCPU *cpu;
     target_ulong pc;
 
     /* Decoder.  */
@@ -327,8 +327,8 @@
     int l1;
 
     if ((dc->tb_flags & MSR_EE_FLAG)
-          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-          && !((dc->env->pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
+          && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
     }
@@ -370,7 +370,7 @@
             }
             break;
         default:
-            cpu_abort(dc->env,
+            cpu_abort(CPU(dc->cpu),
                       "unsupported pattern insn opcode=%x\n", dc->opcode);
             break;
     }
@@ -441,9 +441,10 @@
 
 static void dec_msr(DisasContext *dc)
 {
+    CPUState *cs = CPU(dc->cpu);
     TCGv t0, t1;
     unsigned int sr, to, rn;
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     sr = dc->imm & ((1 << 14) - 1);
     to = dc->imm & (1 << 14);
@@ -458,7 +459,7 @@
         LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
                 dc->rd, dc->imm);
 
-        if (!(dc->env->pvr.regs[2] & PVR2_USE_MSR_INSTR)) {
+        if (!(dc->cpu->env.pvr.regs[2] & PVR2_USE_MSR_INSTR)) {
             /* nop??? */
             return;
         }
@@ -537,7 +538,7 @@
                 tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, shr));
                 break;
             default:
-                cpu_abort(dc->env, "unknown mts reg %x\n", sr);
+                cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
                 break;
         }
     } else {
@@ -586,7 +587,7 @@
                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
                 break;
             default:
-                cpu_abort(dc->env, "unknown mfs reg %x\n", sr);
+                cpu_abort(cs, "unknown mfs reg %x\n", sr);
                 break;
         }
     }
@@ -643,8 +644,8 @@
     unsigned int subcode;
 
     if ((dc->tb_flags & MSR_EE_FLAG)
-         && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-         && !(dc->env->pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
+         && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+         && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
         return;
@@ -662,7 +663,7 @@
 
     /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2.  */
     if (subcode >= 1 && subcode <= 3
-        && !((dc->env->pvr.regs[2] & PVR2_USE_MUL64_MASK))) {
+        && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_MUL64_MASK))) {
         /* nop??? */
     }
 
@@ -684,7 +685,7 @@
             t_gen_mulu(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
             break;
         default:
-            cpu_abort(dc->env, "unknown MUL insn %x\n", subcode);
+            cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
             break;
     }
 done:
@@ -700,8 +701,8 @@
     u = dc->imm & 2; 
     LOG_DIS("div\n");
 
-    if ((dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-          && !((dc->env->pvr.regs[0] & PVR0_USE_DIV_MASK))) {
+    if ((dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !((dc->cpu->env.pvr.regs[0] & PVR0_USE_DIV_MASK))) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
     }
@@ -722,8 +723,8 @@
     unsigned int s, t;
 
     if ((dc->tb_flags & MSR_EE_FLAG)
-          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-          && !(dc->env->pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
+          && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
         return;
@@ -752,9 +753,10 @@
 
 static void dec_bit(DisasContext *dc)
 {
+    CPUState *cs = CPU(dc->cpu);
     TCGv t0;
     unsigned int op;
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     op = dc->ir & ((1 << 9) - 1);
     switch (op) {
@@ -819,12 +821,12 @@
             break;
         case 0xe0:
             if ((dc->tb_flags & MSR_EE_FLAG)
-                && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-                && !((dc->env->pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
+                && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+                && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
                 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
                 t_gen_raise_exception(dc, EXCP_HW_EXCP);
             }
-            if (dc->env->pvr.regs[2] & PVR2_USE_PCMP_INSTR) {
+            if (dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR) {
                 gen_helper_clz(cpu_R[dc->rd], cpu_R[dc->ra]);
             }
             break;
@@ -839,8 +841,8 @@
             tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16);
             break;
         default:
-            cpu_abort(dc->env, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
-                     dc->pc, op, dc->rd, dc->ra, dc->rb);
+            cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
+                      dc->pc, op, dc->rd, dc->ra, dc->rb);
             break;
     }
 }
@@ -933,7 +935,7 @@
     }
 
     if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
-          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+          && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
         return;
@@ -991,7 +993,7 @@
                 }
                 break;
             default:
-                cpu_abort(dc->env, "Invalid reverse size\n");
+                cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
                 break;
         }
     }
@@ -1018,9 +1020,9 @@
      * address and if that succeeds we write into the destination reg.
      */
     v = tcg_temp_new();
-    tcg_gen_qemu_ld_tl(v, *addr, cpu_mmu_index(dc->env), mop);
+    tcg_gen_qemu_ld_tl(v, *addr, cpu_mmu_index(&dc->cpu->env), mop);
 
-    if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+    if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
         tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
         gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
                             tcg_const_tl(0), tcg_const_tl(size - 1));
@@ -1063,7 +1065,7 @@
     }
 
     if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
-          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+          && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
         return;
@@ -1096,7 +1098,8 @@
            this compare and the following write to be atomic. For user
            emulation we need to add atomicity between threads.  */
         tval = tcg_temp_new();
-        tcg_gen_qemu_ld_tl(tval, swx_addr, cpu_mmu_index(dc->env), MO_TEUL);
+        tcg_gen_qemu_ld_tl(tval, swx_addr, cpu_mmu_index(&dc->cpu->env),
+                           MO_TEUL);
         tcg_gen_brcond_tl(TCG_COND_NE, env_res_val, tval, swx_skip);
         write_carryi(dc, 0);
         tcg_temp_free(tval);
@@ -1142,14 +1145,14 @@
                 }
                 break;
             default:
-                cpu_abort(dc->env, "Invalid reverse size\n");
+                cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
                 break;
         }
     }
-    tcg_gen_qemu_st_tl(cpu_R[dc->rd], *addr, cpu_mmu_index(dc->env), mop);
+    tcg_gen_qemu_st_tl(cpu_R[dc->rd], *addr, cpu_mmu_index(&dc->cpu->env), mop);
 
     /* Verify alignment if needed.  */
-    if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+    if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
         tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
         /* FIXME: if the alignment is wrong, we should restore the value
          *        in memory. One possible way to achieve this is to probe
@@ -1193,7 +1196,7 @@
             tcg_gen_setcond_tl(TCG_COND_GT, d, a, b);
             break;
         default:
-            cpu_abort(dc->env, "Unknown condition code %x.\n", cc);
+            cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
             break;
     }
 }
@@ -1244,7 +1247,7 @@
 static void dec_br(DisasContext *dc)
 {
     unsigned int dslot, link, abs, mbar;
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     dslot = dc->ir & (1 << 20);
     abs = dc->ir & (1 << 19);
@@ -1376,7 +1379,7 @@
 static void dec_rts(DisasContext *dc)
 {
     unsigned int b_bit, i_bit, e_bit;
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
 
     i_bit = dc->ir & (1 << 21);
     b_bit = dc->ir & (1 << 22);
@@ -1423,7 +1426,7 @@
 {
     int r;
 
-    r = dc->env->pvr.regs[2] & PVR2_USE_FPU2_MASK;
+    r = dc->cpu->env.pvr.regs[2] & PVR2_USE_FPU2_MASK;
 
     if (!r && (dc->tb_flags & MSR_EE_FLAG)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
@@ -1437,8 +1440,8 @@
     unsigned int fpu_insn;
 
     if ((dc->tb_flags & MSR_EE_FLAG)
-          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-          && !((dc->env->pvr.regs[2] & PVR2_USE_FPU_MASK))) {
+          && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_FPU_MASK))) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
         return;
@@ -1540,7 +1543,7 @@
 static void dec_null(DisasContext *dc)
 {
     if ((dc->tb_flags & MSR_EE_FLAG)
-          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+          && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
         return;
@@ -1552,7 +1555,7 @@
 /* Insns connected to FSL or AXI stream attached devices.  */
 static void dec_stream(DisasContext *dc)
 {
-    int mem_index = cpu_mmu_index(dc->env);
+    int mem_index = cpu_mmu_index(&dc->cpu->env);
     TCGv_i32 t_id, t_ctrl;
     int ctrl;
 
@@ -1628,8 +1631,8 @@
         dc->nr_nops = 0;
     else {
         if ((dc->tb_flags & MSR_EE_FLAG)
-              && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-              && (dc->env->pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
+              && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+              && (dc->cpu->env.pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
             t_gen_raise_exception(dc, EXCP_HW_EXCP);
             return;
@@ -1637,8 +1640,9 @@
 
         LOG_DIS("nr_nops=%d\t", dc->nr_nops);
         dc->nr_nops++;
-        if (dc->nr_nops > 4)
-            cpu_abort(dc->env, "fetching nop sequence\n");
+        if (dc->nr_nops > 4) {
+            cpu_abort(CPU(dc->cpu), "fetching nop sequence\n");
+        }
     }
     /* bit 2 seems to indicate insn type.  */
     dc->type_b = ir & (1 << 29);
@@ -1660,10 +1664,11 @@
 
 static void check_breakpoint(CPUMBState *env, DisasContext *dc)
 {
+    CPUState *cs = CPU(mb_env_get_cpu(env));
     CPUBreakpoint *bp;
 
-    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+    if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == dc->pc) {
                 t_gen_raise_exception(dc, EXCP_DEBUG);
                 dc->is_jmp = DISAS_UPDATE;
@@ -1690,7 +1695,7 @@
     int max_insns;
 
     pc_start = tb->pc;
-    dc->env = env;
+    dc->cpu = cpu;
     dc->tb = tb;
     org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
 
@@ -1708,8 +1713,9 @@
     dc->abort_at_next_insn = 0;
     dc->nr_nops = 0;
 
-    if (pc_start & 3)
-        cpu_abort(env, "Microblaze: unaligned PC=%x\n", pc_start);
+    if (pc_start & 3) {
+        cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
+    }
 
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
 #if !SIM_COMPAT
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 9dd47e8..ae37ae2 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -45,6 +45,35 @@
     env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
 }
 
+static bool mips_cpu_has_work(CPUState *cs)
+{
+    MIPSCPU *cpu = MIPS_CPU(cs);
+    CPUMIPSState *env = &cpu->env;
+    bool has_work = false;
+
+    /* 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 ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
+        cpu_mips_hw_interrupts_pending(env)) {
+        has_work = true;
+    }
+
+    /* MIPS-MT has the ability to halt the CPU.  */
+    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+        /* The QEMU model will issue an _WAKE request whenever the CPUs
+           should be woken up.  */
+        if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
+            has_work = true;
+        }
+
+        if (!mips_vpe_active(env)) {
+            has_work = false;
+        }
+    }
+    return has_work;
+}
+
 /* CPUClass::reset() */
 static void mips_cpu_reset(CPUState *s)
 {
@@ -54,8 +83,8 @@
 
     mcc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUMIPSState, breakpoints));
-    tlb_flush(env, 1);
+    memset(env, 0, offsetof(CPUMIPSState, mvp));
+    tlb_flush(s, 1);
 
     cpu_state_reset(env);
 }
@@ -97,13 +126,16 @@
     mcc->parent_reset = cc->reset;
     cc->reset = mips_cpu_reset;
 
+    cc->has_work = mips_cpu_has_work;
     cc->do_interrupt = mips_cpu_do_interrupt;
     cc->dump_state = mips_cpu_dump_state;
     cc->set_pc = mips_cpu_set_pc;
     cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
     cc->gdb_read_register = mips_cpu_gdb_read_register;
     cc->gdb_write_register = mips_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = mips_cpu_handle_mmu_fault;
+#else
     cc->do_unassigned_access = mips_cpu_unassigned_access;
     cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
 #endif
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 60c8061..3ba3229 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -482,6 +482,7 @@
 
     CPU_COMMON
 
+    /* Fields from here on are preserved across CPU reset. */
     CPUMIPSMVPContext *mvp;
 #if !defined(CONFIG_USER_ONLY)
     CPUMIPSTLBContext *tlb;
@@ -666,9 +667,8 @@
 void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level);
 
 /* helper.c */
-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
+int mips_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                              int mmu_idx);
 #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,
@@ -715,34 +715,6 @@
     return active;
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    CPUMIPSState *env = &MIPS_CPU(cpu)->env;
-    bool has_work = false;
-
-    /* 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 ((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
-        cpu_mips_hw_interrupts_pending(env)) {
-        has_work = true;
-    }
-
-    /* MIPS-MT has the ability to halt the CPU.  */
-    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
-        /* The QEMU model will issue an _WAKE request whenever the CPUs
-           should be woken up.  */
-        if (cpu->interrupt_request & CPU_INTERRUPT_WAKE) {
-            has_work = true;
-        }
-
-        if (!mips_vpe_active(env)) {
-            has_work = false;
-        }
-    }
-    return has_work;
-}
-
 #include "exec/exec-all.h"
 
 static inline void compute_hflags(CPUMIPSState *env)
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 33e0e88..b28ae9b 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -204,6 +204,7 @@
 static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
                                 int rw, int tlb_error)
 {
+    CPUState *cs = CPU(mips_env_get_cpu(env));
     int exception = 0, error_code = 0;
 
     switch (tlb_error) {
@@ -249,7 +250,7 @@
                         ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
                         ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
 #endif
-    env->exception_index = exception;
+    cs->exception_index = exception;
     env->error_code = error_code;
 }
 
@@ -268,9 +269,11 @@
 }
 #endif
 
-int cpu_mips_handle_mmu_fault (CPUMIPSState *env, target_ulong address, int rw,
-                               int mmu_idx)
+int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                              int mmu_idx)
 {
+    MIPSCPU *cpu = MIPS_CPU(cs);
+    CPUMIPSState *env = &cpu->env;
 #if !defined(CONFIG_USER_ONLY)
     hwaddr physical;
     int prot;
@@ -279,9 +282,9 @@
     int ret = 0;
 
 #if 0
-    log_cpu_state(CPU(mips_env_get_cpu(env)), 0);
+    log_cpu_state(cs, 0);
 #endif
-    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d\n",
+    qemu_log("%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
               __func__, env->active_tc.PC, address, rw, mmu_idx);
 
     rw &= 1;
@@ -293,10 +296,11 @@
     access_type = ACCESS_INT;
     ret = get_physical_address(env, &physical, &prot,
                                address, rw, access_type);
-    qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_plx " prot %d\n",
-              __func__, address, ret, physical, prot);
+    qemu_log("%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
+             " prot %d\n",
+             __func__, address, ret, physical, prot);
     if (ret == TLBRET_MATCH) {
-        tlb_set_page(env, address & TARGET_PAGE_MASK,
+        tlb_set_page(cs, address & TARGET_PAGE_MASK,
                      physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
                      mmu_idx, TARGET_PAGE_SIZE);
         ret = 0;
@@ -401,27 +405,29 @@
 
 void mips_cpu_do_interrupt(CPUState *cs)
 {
+#if !defined(CONFIG_USER_ONLY)
     MIPSCPU *cpu = MIPS_CPU(cs);
     CPUMIPSState *env = &cpu->env;
-#if !defined(CONFIG_USER_ONLY)
     target_ulong offset;
     int cause = -1;
     const char *name;
 
-    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
-        if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
+    if (qemu_log_enabled() && cs->exception_index != EXCP_EXT_INTERRUPT) {
+        if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) {
             name = "unknown";
-        else
-            name = excp_names[env->exception_index];
+        } else {
+            name = excp_names[cs->exception_index];
+        }
 
         qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
                  __func__, env->active_tc.PC, env->CP0_EPC, name);
     }
-    if (env->exception_index == EXCP_EXT_INTERRUPT &&
-        (env->hflags & MIPS_HFLAG_DM))
-        env->exception_index = EXCP_DINT;
+    if (cs->exception_index == EXCP_EXT_INTERRUPT &&
+        (env->hflags & MIPS_HFLAG_DM)) {
+        cs->exception_index = EXCP_DINT;
+    }
     offset = 0x180;
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXCP_DSS:
         env->CP0_Debug |= 1 << CP0DB_DSS;
         /* Debug single step cannot be raised inside a delay slot and
@@ -629,11 +635,11 @@
         env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
         break;
     default:
-        qemu_log("Invalid MIPS exception %d. Exiting\n", env->exception_index);
-        printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
+        qemu_log("Invalid MIPS exception %d. Exiting\n", cs->exception_index);
+        printf("Invalid MIPS exception %d. Exiting\n", cs->exception_index);
         exit(1);
     }
-    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
+    if (qemu_log_enabled() && cs->exception_index != EXCP_EXT_INTERRUPT) {
         qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
                 "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
                 __func__, env->active_tc.PC, env->CP0_EPC, cause,
@@ -641,12 +647,14 @@
                 env->CP0_DEPC);
     }
 #endif
-    env->exception_index = EXCP_NONE;
+    cs->exception_index = EXCP_NONE;
 }
 
 #if !defined(CONFIG_USER_ONLY)
 void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra)
 {
+    MIPSCPU *cpu = mips_env_get_cpu(env);
+    CPUState *cs;
     r4k_tlb_t *tlb;
     target_ulong addr;
     target_ulong end;
@@ -672,6 +680,7 @@
     /* 1k pages are not supported. */
     mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
     if (tlb->V0) {
+        cs = CPU(cpu);
         addr = tlb->VPN & ~mask;
 #if defined(TARGET_MIPS64)
         if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
@@ -680,11 +689,12 @@
 #endif
         end = addr | (mask >> 1);
         while (addr < end) {
-            tlb_flush_page (env, addr);
+            tlb_flush_page(cs, addr);
             addr += TARGET_PAGE_SIZE;
         }
     }
     if (tlb->V1) {
+        cs = CPU(cpu);
         addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
 #if defined(TARGET_MIPS64)
         if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
@@ -693,7 +703,7 @@
 #endif
         end = addr | mask;
         while (addr - 1 < end) {
-            tlb_flush_page (env, addr);
+            tlb_flush_page(cs, addr);
             addr += TARGET_PAGE_SIZE;
         }
     }
diff --git a/target-mips/machine.c b/target-mips/machine.c
index 23504ba..0a07db8 100644
--- a/target-mips/machine.c
+++ b/target-mips/machine.c
@@ -191,6 +191,7 @@
 int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
     CPUMIPSState *env = opaque;
+    MIPSCPU *cpu = mips_env_get_cpu(env);
     int i;
 
     if (version_id != 3)
@@ -303,6 +304,6 @@
         load_fpu(f, &env->fpus[i]);
 
     /* XXX: ensure compatibility for halted bit ? */
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
     return 0;
 }
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 2ef6633..e56f038 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -38,18 +38,20 @@
                                                         int error_code,
                                                         uintptr_t pc)
 {
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+
     if (exception < EXCP_SC) {
         qemu_log("%s: %d %d\n", __func__, exception, error_code);
     }
-    env->exception_index = exception;
+    cs->exception_index = exception;
     env->error_code = error_code;
 
     if (pc) {
         /* now we have a real cpu fault */
-        cpu_restore_state(env, pc);
+        cpu_restore_state(cs, pc);
     }
 
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
@@ -278,7 +280,7 @@
     lladdr = cpu_mips_translate_address(env, address, rw);
 
     if (lladdr == -1LL) {
-        cpu_loop_exit(env);
+        cpu_loop_exit(CPU(mips_env_get_cpu(env)));
     } else {
         return lladdr;
     }
@@ -1342,6 +1344,7 @@
 
 void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
 {
+    MIPSCPU *cpu = mips_env_get_cpu(env);
     uint32_t val, old;
     uint32_t mask = env->CP0_Status_rw_bitmask;
 
@@ -1363,7 +1366,9 @@
         case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
         case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
         case MIPS_HFLAG_KM: qemu_log("\n"); break;
-        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
+        default:
+            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
+            break;
         }
     }
 }
@@ -1782,8 +1787,10 @@
 /* TLB management */
 static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
 {
+    MIPSCPU *cpu = mips_env_get_cpu(env);
+
     /* Flush qemu's TLB and discard all shadowed entries.  */
-    tlb_flush (env, flush_global);
+    tlb_flush(CPU(cpu), flush_global);
     env->tlb->tlb_in_use = env->tlb->nb_tlb;
 }
 
@@ -1983,6 +1990,8 @@
 
 static void debug_post_eret(CPUMIPSState *env)
 {
+    MIPSCPU *cpu = mips_env_get_cpu(env);
+
     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
         qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
                 env->active_tc.PC, env->CP0_EPC);
@@ -1994,7 +2003,9 @@
         case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
         case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
         case MIPS_HFLAG_KM: qemu_log("\n"); break;
-        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
+        default:
+            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
+            break;
         }
     }
 }
@@ -2143,14 +2154,17 @@
     do_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL, retaddr);
 }
 
-void tlb_fill(CPUMIPSState *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = mips_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (ret) {
-        do_raise_exception_err(env, env->exception_index,
+        MIPSCPU *cpu = MIPS_CPU(cs);
+        CPUMIPSState *env = &cpu->env;
+
+        do_raise_exception_err(env, cs->exception_index,
                                env->error_code, retaddr);
     }
 }
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 083f6ab..71dccae 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -15613,8 +15613,8 @@
     LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags);
     gen_tb_start();
     while (ctx.bstate == BS_NONE) {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == ctx.pc) {
                     save_cpu_state(&ctx, 1);
                     ctx.bstate = BS_BRANCH;
@@ -15929,10 +15929,8 @@
 
 void cpu_state_reset(CPUMIPSState *env)
 {
-#ifndef CONFIG_USER_ONLY
     MIPSCPU *cpu = mips_env_get_cpu(env);
     CPUState *cs = CPU(cpu);
-#endif
 
     /* Reset registers to their default values */
     env->CP0_PRid = env->cpu_model->CP0_PRid;
@@ -16063,7 +16061,7 @@
     }
 #endif
     compute_hflags(env);
-    env->exception_index = EXCP_NONE;
+    cs->exception_index = EXCP_NONE;
 }
 
 void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos)
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 29d39e2..a64fd2b 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -629,6 +629,8 @@
 
 static void mmu_init (CPUMIPSState *env, const mips_def_t *def)
 {
+    MIPSCPU *cpu = mips_env_get_cpu(env);
+
     env->tlb = g_malloc0(sizeof(CPUMIPSTLBContext));
 
     switch (def->mmu_type) {
@@ -645,7 +647,7 @@
         case MMU_TYPE_R6000:
         case MMU_TYPE_R8000:
         default:
-            cpu_abort(env, "MMU type not supported\n");
+            cpu_abort(CPU(cpu), "MMU type not supported\n");
     }
 }
 #endif /* CONFIG_USER_ONLY */
diff --git a/target-moxie/cpu.c b/target-moxie/cpu.c
index 484ecc2..47b617f 100644
--- a/target-moxie/cpu.c
+++ b/target-moxie/cpu.c
@@ -29,6 +29,11 @@
     cpu->env.pc = value;
 }
 
+static bool moxie_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
 static void moxie_cpu_reset(CPUState *s)
 {
     MoxieCPU *cpu = MOXIE_CPU(s);
@@ -37,10 +42,10 @@
 
     mcc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUMoxieState, breakpoints));
+    memset(env, 0, sizeof(CPUMoxieState));
     env->pc = 0x1000;
 
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 }
 
 static void moxie_cpu_realizefn(DeviceState *dev, Error **errp)
@@ -99,10 +104,13 @@
 
     cc->class_by_name = moxie_cpu_class_by_name;
 
+    cc->has_work = moxie_cpu_has_work;
     cc->do_interrupt = moxie_cpu_do_interrupt;
     cc->dump_state = moxie_cpu_dump_state;
     cc->set_pc = moxie_cpu_set_pc;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = moxie_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
     cc->vmsd = &vmstate_moxie_cpu;
 #endif
@@ -130,18 +138,7 @@
 
 MoxieCPU *cpu_moxie_init(const char *cpu_model)
 {
-    MoxieCPU *cpu;
-    ObjectClass *oc;
-
-    oc = moxie_cpu_class_by_name(cpu_model);
-    if (oc == NULL) {
-        return NULL;
-    }
-    cpu = MOXIE_CPU(object_new(object_class_get_name(oc)));
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return cpu;
+    return MOXIE_CPU(cpu_generic_init(TYPE_MOXIE_CPU, cpu_model));
 }
 
 static void cpu_register(const MoxieCPUInfo *info)
diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h
index 5ce14b5..c5b12a5 100644
--- a/target-moxie/cpu.h
+++ b/target-moxie/cpu.h
@@ -152,12 +152,7 @@
     *flags = 0;
 }
 
-static inline int cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request & CPU_INTERRUPT_HARD;
-}
-
-int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
+int moxie_cpu_handle_mmu_fault(CPUState *cpu, vaddr address,
                                int rw, int mmu_idx);
 
 #endif /* _CPU_MOXIE_H */
diff --git a/target-moxie/helper.c b/target-moxie/helper.c
index 7859102..3d0c34d 100644
--- a/target-moxie/helper.c
+++ b/target-moxie/helper.c
@@ -46,31 +46,33 @@
 /* Try to fill the TLB and return an exception if error. If retaddr is
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
-void tlb_fill(CPUMoxieState *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_moxie_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = moxie_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
     }
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void helper_raise_exception(CPUMoxieState *env, int ex)
 {
-    env->exception_index = ex;
+    CPUState *cs = CPU(moxie_env_get_cpu(env));
+
+    cs->exception_index = ex;
     /* Stash the exception type.  */
     env->sregs[2] = ex;
     /* Stash the address where the exception occurred.  */
-    cpu_restore_state(env, GETPC());
+    cpu_restore_state(cs, GETPC());
     env->sregs[5] = env->pc;
     /* Jump the the exception handline routine.  */
     env->pc = env->sregs[1];
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 uint32_t helper_div(CPUMoxieState *env, uint32_t a, uint32_t b)
@@ -97,33 +99,39 @@
 
 void helper_debug(CPUMoxieState *env)
 {
-    env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(moxie_env_get_cpu(env));
+
+    cs->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(cs);
 }
 
 #if defined(CONFIG_USER_ONLY)
 
-void moxie_cpu_do_interrupt(CPUState *env)
+void moxie_cpu_do_interrupt(CPUState *cs)
 {
-    env->exception_index = -1;
+    CPUState *cs = CPU(moxie_env_get_cpu(env));
+
+    cs->exception_index = -1;
 }
 
-int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
+int moxie_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
                                int rw, int mmu_idx)
 {
-    MoxieCPU *cpu = moxie_env_get_cpu(env);
+    MoxieCPU *cpu = MOXIE_CPU(cs);
 
-    env->exception_index = 0xaa;
-    env->debug1 = address;
-    cpu_dump_state(CPU(cpu), stderr, fprintf, 0);
+    cs->exception_index = 0xaa;
+    cpu->env.debug1 = address;
+    cpu_dump_state(cs, stderr, fprintf, 0);
     return 1;
 }
 
 #else /* !CONFIG_USER_ONLY */
 
-int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
+int moxie_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
                                int rw, int mmu_idx)
 {
+    MoxieCPU *cpu = MOXIE_CPU(cs);
+    CPUMoxieState *env = &cpu->env;
     MoxieMMUResult res;
     int prot, miss;
     target_ulong phy;
@@ -135,22 +143,19 @@
     if (miss) {
         /* handle the miss.  */
         phy = 0;
-        env->exception_index = MOXIE_EX_MMU_MISS;
+        cs->exception_index = MOXIE_EX_MMU_MISS;
     } else {
         phy = res.phy;
         r = 0;
     }
-    tlb_set_page(env, address, phy, prot, mmu_idx, TARGET_PAGE_SIZE);
+    tlb_set_page(cs, address, phy, prot, mmu_idx, TARGET_PAGE_SIZE);
     return r;
 }
 
 
 void moxie_cpu_do_interrupt(CPUState *cs)
 {
-    MoxieCPU *cpu = MOXIE_CPU(cs);
-    CPUMoxieState *env = &cpu->env;
-
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case MOXIE_EX_BREAK:
         break;
     default:
diff --git a/target-moxie/translate.c b/target-moxie/translate.c
index a93196f..63f889f 100644
--- a/target-moxie/translate.c
+++ b/target-moxie/translate.c
@@ -845,8 +845,8 @@
 
     gen_tb_start();
     do {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (ctx.pc == bp->pc) {
                     tcg_gen_movi_i32(cpu_pc, ctx.pc);
                     gen_helper_debug(cpu_env);
diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c
index 8137943..08e724c 100644
--- a/target-openrisc/cpu.c
+++ b/target-openrisc/cpu.c
@@ -27,6 +27,12 @@
     cpu->env.pc = value;
 }
 
+static bool openrisc_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & (CPU_INTERRUPT_HARD |
+                                    CPU_INTERRUPT_TIMER);
+}
+
 /* CPUClass::reset() */
 static void openrisc_cpu_reset(CPUState *s)
 {
@@ -35,14 +41,18 @@
 
     occ->parent_reset(s);
 
-    memset(&cpu->env, 0, offsetof(CPUOpenRISCState, breakpoints));
+#ifndef CONFIG_USER_ONLY
+    memset(&cpu->env, 0, offsetof(CPUOpenRISCState, tlb));
+#else
+    memset(&cpu->env, 0, offsetof(CPUOpenRISCState, irq));
+#endif
 
-    tlb_flush(&cpu->env, 1);
+    tlb_flush(s, 1);
     /*tb_flush(&cpu->env);    FIXME: Do we need it?  */
 
     cpu->env.pc = 0x100;
     cpu->env.sr = SR_FO | SR_SM;
-    cpu->env.exception_index = -1;
+    s->exception_index = -1;
 
     cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP;
     cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S;
@@ -153,12 +163,15 @@
     cc->reset = openrisc_cpu_reset;
 
     cc->class_by_name = openrisc_cpu_class_by_name;
+    cc->has_work = openrisc_cpu_has_work;
     cc->do_interrupt = openrisc_cpu_do_interrupt;
     cc->dump_state = openrisc_cpu_dump_state;
     cc->set_pc = openrisc_cpu_set_pc;
     cc->gdb_read_register = openrisc_cpu_gdb_read_register;
     cc->gdb_write_register = openrisc_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = openrisc_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
     dc->vmsd = &vmstate_openrisc_cpu;
 #endif
@@ -201,18 +214,7 @@
 
 OpenRISCCPU *cpu_openrisc_init(const char *cpu_model)
 {
-    OpenRISCCPU *cpu;
-    ObjectClass *oc;
-
-    oc = openrisc_cpu_class_by_name(cpu_model);
-    if (oc == NULL) {
-        return NULL;
-    }
-    cpu = OPENRISC_CPU(object_new(object_class_get_name(oc)));
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return cpu;
+    return OPENRISC_CPU(cpu_generic_init(TYPE_OPENRISC_CPU, cpu_model));
 }
 
 /* Sort alphabetically by type name, except for "any". */
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 51d6afd..4512f45 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -304,6 +304,7 @@
 
     CPU_COMMON
 
+    /* Fields from here on are preserved across CPU reset. */
 #ifndef CONFIG_USER_ONLY
     CPUOpenRISCTLBContext * tlb;
 
@@ -353,15 +354,13 @@
 int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
 int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void openrisc_translate_init(void);
-int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
-                                  target_ulong address,
+int openrisc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address,
                                   int rw, int mmu_idx);
 int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc);
 
 #define cpu_list cpu_openrisc_list
 #define cpu_exec cpu_openrisc_exec
 #define cpu_gen_code cpu_openrisc_gen_code
-#define cpu_handle_mmu_fault cpu_openrisc_handle_mmu_fault
 #define cpu_signal_handler cpu_openrisc_signal_handler
 
 #ifndef CONFIG_USER_ONLY
@@ -419,11 +418,6 @@
 }
 
 #define CPU_INTERRUPT_TIMER   CPU_INTERRUPT_TGT_INT_0
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request & (CPU_INTERRUPT_HARD |
-                                     CPU_INTERRUPT_TIMER);
-}
 
 #include "exec/exec-all.h"
 
diff --git a/target-openrisc/exception.c b/target-openrisc/exception.c
index 58e53c6..74652a5 100644
--- a/target-openrisc/exception.c
+++ b/target-openrisc/exception.c
@@ -22,6 +22,8 @@
 
 void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp)
 {
-    cpu->env.exception_index = excp;
-    cpu_loop_exit(&cpu->env);
+    CPUState *cs = CPU(cpu);
+
+    cs->exception_index = excp;
+    cpu_loop_exit(cs);
 }
diff --git a/target-openrisc/interrupt.c b/target-openrisc/interrupt.c
index 2153e7e..3de567e 100644
--- a/target-openrisc/interrupt.c
+++ b/target-openrisc/interrupt.c
@@ -27,9 +27,9 @@
 
 void openrisc_cpu_do_interrupt(CPUState *cs)
 {
+#ifndef CONFIG_USER_ONLY
     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
     CPUOpenRISCState *env = &cpu->env;
-#ifndef CONFIG_USER_ONLY
 
     env->epcr = env->pc;
     if (env->flags & D_FLAG) {
@@ -37,13 +37,13 @@
         env->sr |= SR_DSX;
         env->epcr -= 4;
     }
-    if (env->exception_index == EXCP_SYSCALL) {
+    if (cs->exception_index == EXCP_SYSCALL) {
         env->epcr += 4;
     }
 
     /* For machine-state changed between user-mode and supervisor mode,
        we need flush TLB when we enter&exit EXCP.  */
-    tlb_flush(env, 1);
+    tlb_flush(cs, 1);
 
     env->esr = env->sr;
     env->sr &= ~SR_DME;
@@ -54,12 +54,12 @@
     env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
     env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
 
-    if (env->exception_index > 0 && env->exception_index < EXCP_NR) {
-        env->pc = (env->exception_index << 8);
+    if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) {
+        env->pc = (cs->exception_index << 8);
     } else {
-        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
     }
 #endif
 
-    env->exception_index = -1;
+    cs->exception_index = -1;
 }
diff --git a/target-openrisc/interrupt_helper.c b/target-openrisc/interrupt_helper.c
index 844648f..8194057 100644
--- a/target-openrisc/interrupt_helper.c
+++ b/target-openrisc/interrupt_helper.c
@@ -51,7 +51,7 @@
     }
 
     if (need_flush_tlb) {
-        tlb_flush(&cpu->env, 1);
+        tlb_flush(cs, 1);
     }
 #endif
     cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c
index dd487bd..750a936 100644
--- a/target-openrisc/mmu.c
+++ b/target-openrisc/mmu.c
@@ -139,6 +139,7 @@
                                              target_ulong address,
                                              int rw, int tlb_error)
 {
+    CPUState *cs = CPU(cpu);
     int exception = 0;
 
     switch (tlb_error) {
@@ -169,24 +170,24 @@
 #endif
     }
 
-    cpu->env.exception_index = exception;
+    cs->exception_index = exception;
     cpu->env.eear = address;
 }
 
 #ifndef CONFIG_USER_ONLY
-int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
-                                  target_ulong address, int rw, int mmu_idx)
+int openrisc_cpu_handle_mmu_fault(CPUState *cs,
+                                  vaddr address, int rw, int mmu_idx)
 {
+    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
     int ret = 0;
     hwaddr physical = 0;
     int prot = 0;
-    OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
 
     ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
                                      address, rw);
 
     if (ret == TLBRET_MATCH) {
-        tlb_set_page(env, address & TARGET_PAGE_MASK,
+        tlb_set_page(cs, address & TARGET_PAGE_MASK,
                      physical & TARGET_PAGE_MASK, prot,
                      mmu_idx, TARGET_PAGE_SIZE);
         ret = 0;
@@ -198,11 +199,11 @@
     return ret;
 }
 #else
-int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
-                                  target_ulong address, int rw, int mmu_idx)
+int openrisc_cpu_handle_mmu_fault(CPUState *cs,
+                                  vaddr address, int rw, int mmu_idx)
 {
+    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
     int ret = 0;
-    OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
 
     cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
     ret = 1;
diff --git a/target-openrisc/mmu_helper.c b/target-openrisc/mmu_helper.c
index e46b092..fb457c7 100644
--- a/target-openrisc/mmu_helper.c
+++ b/target-openrisc/mmu_helper.c
@@ -36,20 +36,20 @@
 #define SHIFT 3
 #include "exec/softmmu_template.h"
 
-void tlb_fill(CPUOpenRISCState *env, target_ulong addr, int is_write,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write,
               int mmu_idx, uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_openrisc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = openrisc_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
 
     if (ret) {
         if (retaddr) {
             /* now we have a real cpu fault.  */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
         /* Raise Exception.  */
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 #endif
diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
index be06c45..fedcbed 100644
--- a/target-openrisc/sys_helper.c
+++ b/target-openrisc/sys_helper.c
@@ -45,7 +45,7 @@
     case TO_SPR(0, 17): /* SR */
         if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
             (rb & (SR_IME | SR_DME | SR_SM))) {
-            tlb_flush(env, 1);
+            tlb_flush(cs, 1);
         }
         env->sr = rb;
         env->sr |= SR_FO;      /* FO is const equal to 1 */
@@ -84,7 +84,7 @@
     case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
         idx = spr - TO_SPR(1, 512);
         if (!(rb & 1)) {
-            tlb_flush_page(env, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK);
+            tlb_flush_page(cs, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK);
         }
         env->tlb->dtlb[0][idx].mr = rb;
         break;
@@ -103,7 +103,7 @@
     case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1):   /* ITLBW0MR 0-127 */
         idx = spr - TO_SPR(2, 512);
         if (!(rb & 1)) {
-            tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
+            tlb_flush_page(cs, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
         }
         env->tlb->itlb[0][idx].mr = rb;
         break;
diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index 776cb6e..852b5e6 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -1619,10 +1619,11 @@
 
 static void check_breakpoint(OpenRISCCPU *cpu, DisasContext *dc)
 {
+    CPUState *cs = CPU(cpu);
     CPUBreakpoint *bp;
 
-    if (unlikely(!QTAILQ_EMPTY(&cpu->env.breakpoints))) {
-        QTAILQ_FOREACH(bp, &cpu->env.breakpoints, entry) {
+    if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == dc->pc) {
                 tcg_gen_movi_tl(cpu_pc, dc->pc);
                 gen_exception(dc, EXCP_DEBUG);
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index b17c024..47dc8e6 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -38,6 +38,8 @@
 #define POWERPC_CPU_GET_CLASS(obj) \
     OBJECT_GET_CLASS(PowerPCCPUClass, (obj), TYPE_POWERPC_CPU)
 
+typedef struct PowerPCCPU PowerPCCPU;
+
 /**
  * PowerPCCPUClass:
  * @parent_realize: The parent class' realize handler.
@@ -71,7 +73,7 @@
     void (*init_proc)(CPUPPCState *env);
     int  (*check_pow)(CPUPPCState *env);
 #if defined(CONFIG_SOFTMMU)
-    int (*handle_mmu_fault)(CPUPPCState *env, target_ulong eaddr, int rwx,
+    int (*handle_mmu_fault)(PowerPCCPU *cpu, target_ulong eaddr, int rwx,
                             int mmu_idx);
 #endif
 } PowerPCCPUClass;
@@ -83,14 +85,14 @@
  *
  * A PowerPC CPU.
  */
-typedef struct PowerPCCPU {
+struct PowerPCCPU {
     /*< private >*/
     CPUState parent_obj;
     /*< public >*/
 
     CPUPPCState env;
     int cpu_dt_id;
-} PowerPCCPU;
+};
 
 static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
 {
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index afab267..91b7ae5 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1111,8 +1111,8 @@
                             void *puc);
 void ppc_hw_interrupt (CPUPPCState *env);
 #if defined(CONFIG_USER_ONLY)
-int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
-                         int mmu_idx);
+int ppc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                             int mmu_idx);
 #endif
 
 #if !defined(CONFIG_USER_ONLY)
@@ -2100,7 +2100,7 @@
         }
     }
 
-    cpu_abort(env, "Unknown TLBe: %d\n", id);
+    cpu_abort(CPU(ppc_env_get_cpu(env)), "Unknown TLBe: %d\n", id);
     return 0;
 }
 
@@ -2171,14 +2171,6 @@
 
 extern void (*cpu_ppc_hypercall)(PowerPCCPU *);
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
-    CPUPPCState *env = &ppc_cpu->env;
-
-    return msr_ee && (cpu->interrupt_request & CPU_INTERRUPT_HARD);
-}
-
 #include "exec/exec-all.h"
 
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index d541929..19bc6b6 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -43,13 +43,15 @@
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
-    env->exception_index = POWERPC_EXCP_NONE;
+    cs->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 }
 
 void ppc_hw_interrupt(CPUPPCState *env)
 {
-    env->exception_index = POWERPC_EXCP_NONE;
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
+    cs->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 }
 #else /* defined(CONFIG_USER_ONLY) */
@@ -68,8 +70,8 @@
  */
 static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 {
+    CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
-    CPUState *cs;
     target_ulong msr, new_msr, vector;
     int srr0, srr1, asrr0, asrr1;
     int lpes0, lpes1, lev;
@@ -135,7 +137,6 @@
                 fprintf(stderr, "Machine check while not allowed. "
                         "Entering checkstop state\n");
             }
-            cs = CPU(cpu);
             cs->halted = 1;
             cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
         }
@@ -204,7 +205,7 @@
         case POWERPC_EXCP_FP:
             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
                 LOG_EXCP("Ignore floating point exception\n");
-                env->exception_index = POWERPC_EXCP_NONE;
+                cs->exception_index = POWERPC_EXCP_NONE;
                 env->error_code = 0;
                 return;
             }
@@ -241,7 +242,7 @@
             break;
         default:
             /* Should never occur */
-            cpu_abort(env, "Invalid program exception %d. Aborting\n",
+            cpu_abort(cs, "Invalid program exception %d. Aborting\n",
                       env->error_code);
             break;
         }
@@ -301,26 +302,26 @@
             break;
         }
         /* XXX: TODO */
-        cpu_abort(env, "Debug exception is not implemented yet !\n");
+        cpu_abort(cs, "Debug exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_current;
     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
         /* XXX: TODO */
-        cpu_abort(env, "Embedded floating point data exception "
+        cpu_abort(cs, "Embedded floating point data exception "
                   "is not implemented yet !\n");
         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_next;
     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
         /* XXX: TODO */
-        cpu_abort(env, "Embedded floating point round exception "
+        cpu_abort(cs, "Embedded floating point round exception "
                   "is not implemented yet !\n");
         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_next;
     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
         /* XXX: TODO */
-        cpu_abort(env,
+        cpu_abort(cs,
                   "Performance counter exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
@@ -402,15 +403,15 @@
         goto store_next;
     case POWERPC_EXCP_IO:        /* IO error exception                       */
         /* XXX: TODO */
-        cpu_abort(env, "601 IO error exception is not implemented yet !\n");
+        cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
         /* XXX: TODO */
-        cpu_abort(env, "601 run mode exception is not implemented yet !\n");
+        cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
         /* XXX: TODO */
-        cpu_abort(env, "602 emulation trap exception "
+        cpu_abort(cs, "602 emulation trap exception "
                   "is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
@@ -428,7 +429,7 @@
         case POWERPC_EXCP_74xx:
             goto tlb_miss_74xx;
         default:
-            cpu_abort(env, "Invalid instruction TLB miss exception\n");
+            cpu_abort(cs, "Invalid instruction TLB miss exception\n");
             break;
         }
         break;
@@ -447,7 +448,7 @@
         case POWERPC_EXCP_74xx:
             goto tlb_miss_74xx;
         default:
-            cpu_abort(env, "Invalid data load TLB miss exception\n");
+            cpu_abort(cs, "Invalid data load TLB miss exception\n");
             break;
         }
         break;
@@ -533,30 +534,30 @@
             msr |= env->error_code; /* key bit */
             break;
         default:
-            cpu_abort(env, "Invalid data store TLB miss exception\n");
+            cpu_abort(cs, "Invalid data store TLB miss exception\n");
             break;
         }
         goto store_next;
     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
         /* XXX: TODO */
-        cpu_abort(env, "Floating point assist exception "
+        cpu_abort(cs, "Floating point assist exception "
                   "is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
         /* XXX: TODO */
-        cpu_abort(env, "DABR exception is not implemented yet !\n");
+        cpu_abort(cs, "DABR exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
         /* XXX: TODO */
-        cpu_abort(env, "IABR exception is not implemented yet !\n");
+        cpu_abort(cs, "IABR exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_SMI:       /* System management interrupt              */
         /* XXX: TODO */
-        cpu_abort(env, "SMI exception is not implemented yet !\n");
+        cpu_abort(cs, "SMI exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
         /* XXX: TODO */
-        cpu_abort(env, "Thermal management exception "
+        cpu_abort(cs, "Thermal management exception "
                   "is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
@@ -564,36 +565,36 @@
             new_msr |= (target_ulong)MSR_HVB;
         }
         /* XXX: TODO */
-        cpu_abort(env,
+        cpu_abort(cs,
                   "Performance counter exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
         /* XXX: TODO */
-        cpu_abort(env, "VPU assist exception is not implemented yet !\n");
+        cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
         /* XXX: TODO */
-        cpu_abort(env,
+        cpu_abort(cs,
                   "970 soft-patch exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
         /* XXX: TODO */
-        cpu_abort(env,
+        cpu_abort(cs,
                   "970 maintenance exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
         /* XXX: TODO */
-        cpu_abort(env, "Maskable external exception "
+        cpu_abort(cs, "Maskable external exception "
                   "is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
         /* XXX: TODO */
-        cpu_abort(env, "Non maskable external exception "
+        cpu_abort(cs, "Non maskable external exception "
                   "is not implemented yet !\n");
         goto store_next;
     default:
     excp_invalid:
-        cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
+        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
         break;
     store_current:
         /* save current instruction location */
@@ -615,7 +616,7 @@
     }
     /* If we disactivated any translation, flush TLBs */
     if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
     }
 
 #ifdef TARGET_PPC64
@@ -635,7 +636,7 @@
     /* Jump to handler */
     vector = env->excp_vectors[excp];
     if (vector == (target_ulong)-1ULL) {
-        cpu_abort(env, "Raised an exception without defined vector %d\n",
+        cpu_abort(cs, "Raised an exception without defined vector %d\n",
                   excp);
     }
     vector |= env->excp_prefix;
@@ -662,7 +663,7 @@
     hreg_compute_hflags(env);
     env->nip = vector;
     /* Reset exception state */
-    env->exception_index = POWERPC_EXCP_NONE;
+    cs->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 
     if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
@@ -670,7 +671,7 @@
         /* XXX: The BookE changes address space when switching modes,
                 we should probably implement that as different MMU indexes,
                 but for the moment we do it the slow way and flush all.  */
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
     }
 }
 
@@ -679,7 +680,7 @@
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
-    powerpc_excp(cpu, env->excp_model, env->exception_index);
+    powerpc_excp(cpu, env->excp_model, cs->exception_index);
 }
 
 void ppc_hw_interrupt(CPUPPCState *env)
@@ -815,12 +816,14 @@
 void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
                                 uint32_t error_code)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
 #if 0
     printf("Raise exception %3x code : %d\n", exception, error_code);
 #endif
-    env->exception_index = exception;
+    cs->exception_index = exception;
     env->error_code = error_code;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index e7f3295..fd91239 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -119,6 +119,7 @@
 static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
                                              int set_fpcc)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     uint64_t ret = 0;
     int ve;
 
@@ -155,7 +156,7 @@
         }
         /* We must update the target FPR before raising the exception */
         if (ve != 0) {
-            env->exception_index = POWERPC_EXCP_PROGRAM;
+            cs->exception_index = POWERPC_EXCP_PROGRAM;
             env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
             /* Update the floating-point enabled exception summary */
             env->fpscr |= 1 << FPSCR_FEX;
@@ -224,6 +225,8 @@
 
 static inline void float_overflow_excp(CPUPPCState *env)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
     env->fpscr |= 1 << FPSCR_OX;
     /* Update the floating-point exception summary */
     env->fpscr |= 1 << FPSCR_FX;
@@ -232,7 +235,7 @@
         /* Update the floating-point enabled exception summary */
         env->fpscr |= 1 << FPSCR_FEX;
         /* We must update the target FPR before raising the exception */
-        env->exception_index = POWERPC_EXCP_PROGRAM;
+        cs->exception_index = POWERPC_EXCP_PROGRAM;
         env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
     } else {
         env->fpscr |= 1 << FPSCR_XX;
@@ -242,6 +245,8 @@
 
 static inline void float_underflow_excp(CPUPPCState *env)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
     env->fpscr |= 1 << FPSCR_UX;
     /* Update the floating-point exception summary */
     env->fpscr |= 1 << FPSCR_FX;
@@ -250,13 +255,15 @@
         /* Update the floating-point enabled exception summary */
         env->fpscr |= 1 << FPSCR_FEX;
         /* We must update the target FPR before raising the exception */
-        env->exception_index = POWERPC_EXCP_PROGRAM;
+        cs->exception_index = POWERPC_EXCP_PROGRAM;
         env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
     }
 }
 
 static inline void float_inexact_excp(CPUPPCState *env)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
     env->fpscr |= 1 << FPSCR_XX;
     /* Update the floating-point exception summary */
     env->fpscr |= 1 << FPSCR_FX;
@@ -264,7 +271,7 @@
         /* Update the floating-point enabled exception summary */
         env->fpscr |= 1 << FPSCR_FEX;
         /* We must update the target FPR before raising the exception */
-        env->exception_index = POWERPC_EXCP_PROGRAM;
+        cs->exception_index = POWERPC_EXCP_PROGRAM;
         env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
     }
 }
@@ -316,6 +323,7 @@
 
 void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     int prev;
 
     prev = (env->fpscr >> bit) & 1;
@@ -439,7 +447,7 @@
             /* Update the floating-point enabled exception summary */
             env->fpscr |= 1 << FPSCR_FEX;
             /* We have to update Rc1 before raising the exception */
-            env->exception_index = POWERPC_EXCP_PROGRAM;
+            cs->exception_index = POWERPC_EXCP_PROGRAM;
             break;
         }
     }
@@ -447,6 +455,7 @@
 
 void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     target_ulong prev, new;
     int i;
 
@@ -468,7 +477,7 @@
     }
     if ((fpscr_ex & fpscr_eex) != 0) {
         env->fpscr |= 1 << FPSCR_FEX;
-        env->exception_index = POWERPC_EXCP_PROGRAM;
+        cs->exception_index = POWERPC_EXCP_PROGRAM;
         /* XXX: we should compute it properly */
         env->error_code = POWERPC_EXCP_FP;
     } else {
@@ -484,6 +493,7 @@
 
 void helper_float_check_status(CPUPPCState *env)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     int status = get_float_exception_flags(&env->fp_status);
 
     if (status & float_flag_divbyzero) {
@@ -496,11 +506,11 @@
         float_inexact_excp(env);
     }
 
-    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
+    if (cs->exception_index == POWERPC_EXCP_PROGRAM &&
         (env->error_code & POWERPC_EXCP_FP)) {
         /* Differred floating-point exception after target FPR update */
         if (msr_fe0 != 0 || msr_fe1 != 0) {
-            helper_raise_exception_err(env, env->exception_index,
+            helper_raise_exception_err(env, cs->exception_index,
                                        env->error_code);
         }
     }
diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h
index c02e8da..f7ec9c2 100644
--- a/target-ppc/helper_regs.h
+++ b/target-ppc/helper_regs.h
@@ -83,7 +83,7 @@
     if (((value >> MSR_IR) & 1) != msr_ir ||
         ((value >> MSR_DR) & 1) != msr_dr) {
         /* Flush all tlb when changing translation mode */
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
         excp = POWERPC_EXCP_NONE;
         cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
     }
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 32e7a8c..9974b10 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -1178,7 +1178,7 @@
 
     if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
         cs->halted = 1;
-        env->exception_index = EXCP_HLT;
+        cs->exception_index = EXCP_HLT;
     }
 
     return 0;
@@ -1504,7 +1504,6 @@
 
 void kvmppc_set_papr(PowerPCCPU *cpu)
 {
-    CPUPPCState *env = &cpu->env;
     CPUState *cs = CPU(cpu);
     struct kvm_enable_cap cap = {};
     int ret;
@@ -1513,7 +1512,7 @@
     ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
 
     if (ret) {
-        cpu_abort(env, "This KVM version does not support PAPR\n");
+        cpu_abort(cs, "This KVM version does not support PAPR\n");
     }
 
     /* Update the capability flag so we sync the right information
@@ -1523,7 +1522,6 @@
 
 void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
 {
-    CPUPPCState *env = &cpu->env;
     CPUState *cs = CPU(cpu);
     struct kvm_enable_cap cap = {};
     int ret;
@@ -1533,7 +1531,7 @@
     ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
 
     if (ret && mpic_proxy) {
-        cpu_abort(env, "This KVM version does not support EPR\n");
+        cpu_abort(cs, "This KVM version does not support EPR\n");
     }
 }
 
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index dc2ebfc..2eb2fa6 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -62,10 +62,12 @@
 
 void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
     if (likely(env->pb[num] != value)) {
         env->pb[num] = value;
         /* Should be optimized */
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 }
 
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 6a77dc4..1cc1916 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -222,6 +222,7 @@
                                    target_ulong eaddr, int rwx,
                                    hwaddr *raddr, int *prot)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
 
     LOG_MMU("direct store...\n");
@@ -238,7 +239,7 @@
 
     if (rwx == 2) {
         /* No code fetch is allowed in direct-store areas */
-        env->exception_index = POWERPC_EXCP_ISI;
+        cs->exception_index = POWERPC_EXCP_ISI;
         env->error_code = 0x10000000;
         return 1;
     }
@@ -249,7 +250,7 @@
         break;
     case ACCESS_FLOAT:
         /* Floating point load/store */
-        env->exception_index = POWERPC_EXCP_ALIGN;
+        cs->exception_index = POWERPC_EXCP_ALIGN;
         env->error_code = POWERPC_EXCP_ALIGN_FP;
         env->spr[SPR_DAR] = eaddr;
         return 1;
@@ -272,7 +273,7 @@
         return 0;
     case ACCESS_EXT:
         /* eciwx or ecowx */
-        env->exception_index = POWERPC_EXCP_DSI;
+        cs->exception_index = POWERPC_EXCP_DSI;
         env->error_code = 0;
         env->spr[SPR_DAR] = eaddr;
         if (rwx == 1) {
@@ -290,7 +291,7 @@
         *raddr = eaddr;
         return 0;
     } else {
-        env->exception_index = POWERPC_EXCP_DSI;
+        cs->exception_index = POWERPC_EXCP_DSI;
         env->error_code = 0;
         env->spr[SPR_DAR] = eaddr;
         if (rwx == 1) {
@@ -380,9 +381,11 @@
     return (rpn & ~mask) | (eaddr & mask);
 }
 
-int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr, int rwx,
+int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, int rwx,
                                 int mmu_idx)
 {
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
     target_ulong sr;
     hwaddr pte_offset;
     ppc_hash_pte32_t pte;
@@ -397,7 +400,7 @@
     if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
         /* Translation is off */
         raddr = eaddr;
-        tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+        tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
                      PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
                      TARGET_PAGE_SIZE);
         return 0;
@@ -409,10 +412,10 @@
         if (raddr != -1) {
             if (need_prot[rwx] & ~prot) {
                 if (rwx == 2) {
-                    env->exception_index = POWERPC_EXCP_ISI;
+                    cs->exception_index = POWERPC_EXCP_ISI;
                     env->error_code = 0x08000000;
                 } else {
-                    env->exception_index = POWERPC_EXCP_DSI;
+                    cs->exception_index = POWERPC_EXCP_DSI;
                     env->error_code = 0;
                     env->spr[SPR_DAR] = eaddr;
                     if (rwx == 1) {
@@ -424,7 +427,7 @@
                 return 1;
             }
 
-            tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
+            tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
                          raddr & TARGET_PAGE_MASK, prot, mmu_idx,
                          TARGET_PAGE_SIZE);
             return 0;
@@ -438,7 +441,7 @@
     if (sr & SR32_T) {
         if (ppc_hash32_direct_store(env, sr, eaddr, rwx,
                                     &raddr, &prot) == 0) {
-            tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
+            tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
                          raddr & TARGET_PAGE_MASK, prot, mmu_idx,
                          TARGET_PAGE_SIZE);
             return 0;
@@ -449,7 +452,7 @@
 
     /* 5. Check for segment level no-execute violation */
     if ((rwx == 2) && (sr & SR32_NX)) {
-        env->exception_index = POWERPC_EXCP_ISI;
+        cs->exception_index = POWERPC_EXCP_ISI;
         env->error_code = 0x10000000;
         return 1;
     }
@@ -458,10 +461,10 @@
     pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
     if (pte_offset == -1) {
         if (rwx == 2) {
-            env->exception_index = POWERPC_EXCP_ISI;
+            cs->exception_index = POWERPC_EXCP_ISI;
             env->error_code = 0x40000000;
         } else {
-            env->exception_index = POWERPC_EXCP_DSI;
+            cs->exception_index = POWERPC_EXCP_DSI;
             env->error_code = 0;
             env->spr[SPR_DAR] = eaddr;
             if (rwx == 1) {
@@ -483,10 +486,10 @@
         /* Access right violation */
         LOG_MMU("PTE access rejected\n");
         if (rwx == 2) {
-            env->exception_index = POWERPC_EXCP_ISI;
+            cs->exception_index = POWERPC_EXCP_ISI;
             env->error_code = 0x08000000;
         } else {
-            env->exception_index = POWERPC_EXCP_DSI;
+            cs->exception_index = POWERPC_EXCP_DSI;
             env->error_code = 0;
             env->spr[SPR_DAR] = eaddr;
             if (rwx == 1) {
@@ -519,7 +522,7 @@
 
     raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
 
-    tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+    tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
                  prot, mmu_idx, TARGET_PAGE_SIZE);
 
     return 0;
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 4671141..d515d4f 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -5,7 +5,7 @@
 
 hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash);
 hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
-int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, target_ulong address, int rw,
                                 int mmu_idx);
 
 /*
@@ -68,7 +68,8 @@
 static inline target_ulong ppc_hash32_load_hpte0(CPUPPCState *env,
                                                  hwaddr pte_offset)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
     assert(!env->external_htab); /* Not supported on 32-bit for now */
     return ldl_phys(cs->as, env->htab_base + pte_offset);
 }
@@ -76,7 +77,8 @@
 static inline target_ulong ppc_hash32_load_hpte1(CPUPPCState *env,
                                                  hwaddr pte_offset)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
     assert(!env->external_htab); /* Not supported on 32-bit for now */
     return ldl_phys(cs->as, env->htab_base + pte_offset + HASH_PTE_SIZE_32/2);
 }
@@ -84,7 +86,8 @@
 static inline void ppc_hash32_store_hpte0(CPUPPCState *env,
                                           hwaddr pte_offset, target_ulong pte0)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
     assert(!env->external_htab); /* Not supported on 32-bit for now */
     stl_phys(cs->as, env->htab_base + pte_offset, pte0);
 }
@@ -92,7 +95,8 @@
 static inline void ppc_hash32_store_hpte1(CPUPPCState *env,
                                           hwaddr pte_offset, target_ulong pte1)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
+
     assert(!env->external_htab); /* Not supported on 32-bit for now */
     stl_phys(cs->as, env->htab_base + pte_offset + HASH_PTE_SIZE_32/2, pte1);
 }
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index f2af4fb..1fefe58 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -99,6 +99,7 @@
 
 void helper_slbia(CPUPPCState *env)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     int n, do_invalidate;
 
     do_invalidate = 0;
@@ -116,12 +117,13 @@
         }
     }
     if (do_invalidate) {
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 }
 
 void helper_slbie(CPUPPCState *env, target_ulong addr)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     ppc_slb_t *slb;
 
     slb = slb_lookup(env, addr);
@@ -136,7 +138,7 @@
          *      and we still don't have a tlb_flush_mask(env, n, mask)
          *      in QEMU, we just invalidate all TLBs
          */
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 }
 
@@ -454,9 +456,11 @@
     return (rpn & ~mask) | (eaddr & mask);
 }
 
-int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
+int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,
                                 int rwx, int mmu_idx)
 {
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
     ppc_slb_t *slb;
     hwaddr pte_offset;
     ppc_hash_pte64_t pte;
@@ -472,7 +476,7 @@
         /* Translation is off */
         /* In real mode the top 4 effective address bits are ignored */
         raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
-        tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+        tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
                      PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
                      TARGET_PAGE_SIZE);
         return 0;
@@ -483,10 +487,10 @@
 
     if (!slb) {
         if (rwx == 2) {
-            env->exception_index = POWERPC_EXCP_ISEG;
+            cs->exception_index = POWERPC_EXCP_ISEG;
             env->error_code = 0;
         } else {
-            env->exception_index = POWERPC_EXCP_DSEG;
+            cs->exception_index = POWERPC_EXCP_DSEG;
             env->error_code = 0;
             env->spr[SPR_DAR] = eaddr;
         }
@@ -495,7 +499,7 @@
 
     /* 3. Check for segment level no-execute violation */
     if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
-        env->exception_index = POWERPC_EXCP_ISI;
+        cs->exception_index = POWERPC_EXCP_ISI;
         env->error_code = 0x10000000;
         return 1;
     }
@@ -504,10 +508,10 @@
     pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte);
     if (pte_offset == -1) {
         if (rwx == 2) {
-            env->exception_index = POWERPC_EXCP_ISI;
+            cs->exception_index = POWERPC_EXCP_ISI;
             env->error_code = 0x40000000;
         } else {
-            env->exception_index = POWERPC_EXCP_DSI;
+            cs->exception_index = POWERPC_EXCP_DSI;
             env->error_code = 0;
             env->spr[SPR_DAR] = eaddr;
             if (rwx == 1) {
@@ -530,12 +534,12 @@
         /* Access right violation */
         LOG_MMU("PTE access rejected\n");
         if (rwx == 2) {
-            env->exception_index = POWERPC_EXCP_ISI;
+            cs->exception_index = POWERPC_EXCP_ISI;
             env->error_code = 0x08000000;
         } else {
             target_ulong dsisr = 0;
 
-            env->exception_index = POWERPC_EXCP_DSI;
+            cs->exception_index = POWERPC_EXCP_DSI;
             env->error_code = 0;
             env->spr[SPR_DAR] = eaddr;
             if (need_prot[rwx] & ~pp_prot) {
@@ -574,7 +578,7 @@
 
     raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
 
-    tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+    tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
                  prot, mmu_idx, TARGET_PAGE_SIZE);
 
     return 0;
@@ -608,7 +612,7 @@
                            target_ulong pte_index,
                            target_ulong pte0, target_ulong pte1)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
 
     if (kvmppc_kern_htab) {
         return kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 1746b3e..49e385d 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -7,7 +7,7 @@
 void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
 int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
 hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
-int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong address, int rw,
                                 int mmu_idx);
 void ppc_hash64_store_hpte(CPUPPCState *env, target_ulong index,
                            target_ulong pte0, target_ulong pte1);
@@ -85,8 +85,9 @@
 static inline target_ulong ppc_hash64_load_hpte0(CPUPPCState *env,
                                                  uint64_t token, int index)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     uint64_t addr;
+
     addr = token + (index * HASH_PTE_SIZE_64);
     if (env->external_htab) {
         return  ldq_p((const void *)(uintptr_t)addr);
@@ -98,8 +99,9 @@
 static inline target_ulong ppc_hash64_load_hpte1(CPUPPCState *env,
                                                  uint64_t token, int index)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     uint64_t addr;
+
     addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
     if (env->external_htab) {
         return  ldq_p((const void *)(uintptr_t)addr);
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 8e2f8e7..1771863 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -231,6 +231,7 @@
 
 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     ppc6xx_tlb_t *tlb;
     int nr, max;
 
@@ -244,7 +245,7 @@
         tlb = &env->tlb.tlb6[nr];
         pte_invalidate(&tlb->pte0);
     }
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
@@ -252,6 +253,7 @@
                                                int is_code, int match_epn)
 {
 #if !defined(FLUSH_ALL_TLBS)
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     ppc6xx_tlb_t *tlb;
     int way, nr;
 
@@ -263,7 +265,7 @@
             LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
                       env->nb_tlb, eaddr);
             pte_invalidate(&tlb->pte0);
-            tlb_flush_page(env, tlb->EPN);
+            tlb_flush_page(cs, tlb->EPN);
         }
     }
 #else
@@ -643,6 +645,7 @@
 /* Helpers specific to PowerPC 40x implementations */
 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     ppcemb_tlb_t *tlb;
     int i;
 
@@ -650,13 +653,14 @@
         tlb = &env->tlb.tlbe[i];
         tlb->prot &= ~PAGE_VALID;
     }
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
                                               target_ulong eaddr, uint32_t pid)
 {
 #if !defined(FLUSH_ALL_TLBS)
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     ppcemb_tlb_t *tlb;
     hwaddr raddr;
     target_ulong page, end;
@@ -667,7 +671,7 @@
         if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
             end = tlb->EPN + tlb->size;
             for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
-                tlb_flush_page(env, page);
+                tlb_flush_page(cs, page);
             }
             tlb->prot &= ~PAGE_VALID;
             break;
@@ -746,9 +750,11 @@
 
 void store_40x_sler(CPUPPCState *env, uint32_t val)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
     /* XXX: TO BE FIXED */
     if (val != 0x00000000) {
-        cpu_abort(env, "Little-endian regions are not supported by now\n");
+        cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
     }
     env->spr[SPR_405_SLER] = val;
 }
@@ -858,6 +864,7 @@
 static void booke206_flush_tlb(CPUPPCState *env, int flags,
                                const int check_iprot)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     int tlb_size;
     int i, j;
     ppcmas_tlb_t *tlb = env->tlb.tlbm;
@@ -874,7 +881,7 @@
         tlb += booke206_tlb_size(env, i);
     }
 
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
@@ -1344,6 +1351,7 @@
 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
                                 target_ulong eaddr, int rw, int access_type)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     int ret = -1;
     bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
         || (access_type != ACCESS_CODE && msr_dr == 0);
@@ -1388,17 +1396,17 @@
         break;
     case POWERPC_MMU_MPC8xx:
         /* XXX: TODO */
-        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+        cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
         break;
     case POWERPC_MMU_REAL:
         if (real_mode) {
             ret = check_physical(env, ctx, eaddr, rw);
         } else {
-            cpu_abort(env, "PowerPC in real mode do not do any translation\n");
+            cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
         }
         return -1;
     default:
-        cpu_abort(env, "Unknown or invalid MMU model\n");
+        cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
         return -1;
     }
 #if 0
@@ -1491,6 +1499,7 @@
 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
                                     int rw, int mmu_idx)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     mmu_ctx_t ctx;
     int access_type;
     int ret = 0;
@@ -1505,29 +1514,29 @@
     }
     ret = get_physical_address(env, &ctx, address, rw, access_type);
     if (ret == 0) {
-        tlb_set_page(env, address & TARGET_PAGE_MASK,
+        tlb_set_page(cs, address & TARGET_PAGE_MASK,
                      ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
                      mmu_idx, TARGET_PAGE_SIZE);
         ret = 0;
     } else if (ret < 0) {
-        LOG_MMU_STATE(CPU(ppc_env_get_cpu(env)));
+        LOG_MMU_STATE(cs);
         if (access_type == ACCESS_CODE) {
             switch (ret) {
             case -1:
                 /* No matches in page tables or TLB */
                 switch (env->mmu_model) {
                 case POWERPC_MMU_SOFT_6xx:
-                    env->exception_index = POWERPC_EXCP_IFTLB;
+                    cs->exception_index = POWERPC_EXCP_IFTLB;
                     env->error_code = 1 << 18;
                     env->spr[SPR_IMISS] = address;
                     env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
                     goto tlb_miss;
                 case POWERPC_MMU_SOFT_74xx:
-                    env->exception_index = POWERPC_EXCP_IFTLB;
+                    cs->exception_index = POWERPC_EXCP_IFTLB;
                     goto tlb_miss_74xx;
                 case POWERPC_MMU_SOFT_4xx:
                 case POWERPC_MMU_SOFT_4xx_Z:
-                    env->exception_index = POWERPC_EXCP_ITLB;
+                    cs->exception_index = POWERPC_EXCP_ITLB;
                     env->error_code = 0;
                     env->spr[SPR_40x_DEAR] = address;
                     env->spr[SPR_40x_ESR] = 0x00000000;
@@ -1536,26 +1545,26 @@
                     booke206_update_mas_tlb_miss(env, address, rw);
                     /* fall through */
                 case POWERPC_MMU_BOOKE:
-                    env->exception_index = POWERPC_EXCP_ITLB;
+                    cs->exception_index = POWERPC_EXCP_ITLB;
                     env->error_code = 0;
                     env->spr[SPR_BOOKE_DEAR] = address;
                     return -1;
                 case POWERPC_MMU_MPC8xx:
                     /* XXX: TODO */
-                    cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+                    cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
                     break;
                 case POWERPC_MMU_REAL:
-                    cpu_abort(env, "PowerPC in real mode should never raise "
+                    cpu_abort(cs, "PowerPC in real mode should never raise "
                               "any MMU exceptions\n");
                     return -1;
                 default:
-                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    cpu_abort(cs, "Unknown or invalid MMU model\n");
                     return -1;
                 }
                 break;
             case -2:
                 /* Access rights violation */
-                env->exception_index = POWERPC_EXCP_ISI;
+                cs->exception_index = POWERPC_EXCP_ISI;
                 env->error_code = 0x08000000;
                 break;
             case -3:
@@ -1564,13 +1573,13 @@
                     (env->mmu_model == POWERPC_MMU_BOOKE206)) {
                     env->spr[SPR_BOOKE_ESR] = 0x00000000;
                 }
-                env->exception_index = POWERPC_EXCP_ISI;
+                cs->exception_index = POWERPC_EXCP_ISI;
                 env->error_code = 0x10000000;
                 break;
             case -4:
                 /* Direct store exception */
                 /* No code fetch is allowed in direct-store areas */
-                env->exception_index = POWERPC_EXCP_ISI;
+                cs->exception_index = POWERPC_EXCP_ISI;
                 env->error_code = 0x10000000;
                 break;
             }
@@ -1581,10 +1590,10 @@
                 switch (env->mmu_model) {
                 case POWERPC_MMU_SOFT_6xx:
                     if (rw == 1) {
-                        env->exception_index = POWERPC_EXCP_DSTLB;
+                        cs->exception_index = POWERPC_EXCP_DSTLB;
                         env->error_code = 1 << 16;
                     } else {
-                        env->exception_index = POWERPC_EXCP_DLTLB;
+                        cs->exception_index = POWERPC_EXCP_DLTLB;
                         env->error_code = 0;
                     }
                     env->spr[SPR_DMISS] = address;
@@ -1598,9 +1607,9 @@
                     break;
                 case POWERPC_MMU_SOFT_74xx:
                     if (rw == 1) {
-                        env->exception_index = POWERPC_EXCP_DSTLB;
+                        cs->exception_index = POWERPC_EXCP_DSTLB;
                     } else {
-                        env->exception_index = POWERPC_EXCP_DLTLB;
+                        cs->exception_index = POWERPC_EXCP_DLTLB;
                     }
                 tlb_miss_74xx:
                     /* Implement LRU algorithm */
@@ -1611,7 +1620,7 @@
                     break;
                 case POWERPC_MMU_SOFT_4xx:
                 case POWERPC_MMU_SOFT_4xx_Z:
-                    env->exception_index = POWERPC_EXCP_DTLB;
+                    cs->exception_index = POWERPC_EXCP_DTLB;
                     env->error_code = 0;
                     env->spr[SPR_40x_DEAR] = address;
                     if (rw) {
@@ -1622,29 +1631,29 @@
                     break;
                 case POWERPC_MMU_MPC8xx:
                     /* XXX: TODO */
-                    cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+                    cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
                     break;
                 case POWERPC_MMU_BOOKE206:
                     booke206_update_mas_tlb_miss(env, address, rw);
                     /* fall through */
                 case POWERPC_MMU_BOOKE:
-                    env->exception_index = POWERPC_EXCP_DTLB;
+                    cs->exception_index = POWERPC_EXCP_DTLB;
                     env->error_code = 0;
                     env->spr[SPR_BOOKE_DEAR] = address;
                     env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
                     return -1;
                 case POWERPC_MMU_REAL:
-                    cpu_abort(env, "PowerPC in real mode should never raise "
+                    cpu_abort(cs, "PowerPC in real mode should never raise "
                               "any MMU exceptions\n");
                     return -1;
                 default:
-                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    cpu_abort(cs, "Unknown or invalid MMU model\n");
                     return -1;
                 }
                 break;
             case -2:
                 /* Access rights violation */
-                env->exception_index = POWERPC_EXCP_DSI;
+                cs->exception_index = POWERPC_EXCP_DSI;
                 env->error_code = 0;
                 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
                     || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
@@ -1670,13 +1679,13 @@
                 switch (access_type) {
                 case ACCESS_FLOAT:
                     /* Floating point load/store */
-                    env->exception_index = POWERPC_EXCP_ALIGN;
+                    cs->exception_index = POWERPC_EXCP_ALIGN;
                     env->error_code = POWERPC_EXCP_ALIGN_FP;
                     env->spr[SPR_DAR] = address;
                     break;
                 case ACCESS_RES:
                     /* lwarx, ldarx or stwcx. */
-                    env->exception_index = POWERPC_EXCP_DSI;
+                    cs->exception_index = POWERPC_EXCP_DSI;
                     env->error_code = 0;
                     env->spr[SPR_DAR] = address;
                     if (rw == 1) {
@@ -1687,7 +1696,7 @@
                     break;
                 case ACCESS_EXT:
                     /* eciwx or ecowx */
-                    env->exception_index = POWERPC_EXCP_DSI;
+                    cs->exception_index = POWERPC_EXCP_DSI;
                     env->error_code = 0;
                     env->spr[SPR_DAR] = address;
                     if (rw == 1) {
@@ -1698,7 +1707,7 @@
                     break;
                 default:
                     printf("DSI: invalid exception (%d)\n", ret);
-                    env->exception_index = POWERPC_EXCP_PROGRAM;
+                    cs->exception_index = POWERPC_EXCP_PROGRAM;
                     env->error_code =
                         POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
                     env->spr[SPR_DAR] = address;
@@ -1709,7 +1718,7 @@
         }
 #if 0
         printf("%s: set exception to %d %02x\n", __func__,
-               env->exception, env->error_code);
+               cs->exception, env->error_code);
 #endif
         ret = 1;
     }
@@ -1723,6 +1732,7 @@
 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
                                      target_ulong mask)
 {
+    CPUState *cs = CPU(ppc_env_get_cpu(env));
     target_ulong base, end, page;
 
     base = BATu & ~0x0001FFFF;
@@ -1730,7 +1740,7 @@
     LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
              TARGET_FMT_lx ")\n", base, end, mask);
     for (page = base; page != end; page += TARGET_PAGE_SIZE) {
-        tlb_flush_page(env, page);
+        tlb_flush_page(cs, page);
     }
     LOG_BATS("Flush done\n");
 }
@@ -1892,6 +1902,8 @@
 /* TLB management */
 void ppc_tlb_invalidate_all(CPUPPCState *env)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
     switch (env->mmu_model) {
     case POWERPC_MMU_SOFT_6xx:
     case POWERPC_MMU_SOFT_74xx:
@@ -1902,14 +1914,14 @@
         ppc4xx_tlb_invalidate_all(env);
         break;
     case POWERPC_MMU_REAL:
-        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+        cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
         break;
     case POWERPC_MMU_MPC8xx:
         /* XXX: TODO */
-        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+        cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
         break;
     case POWERPC_MMU_BOOKE:
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
         break;
     case POWERPC_MMU_BOOKE206:
         booke206_flush_tlb(env, -1, 0);
@@ -1922,11 +1934,11 @@
     case POWERPC_MMU_2_06a:
     case POWERPC_MMU_2_06d:
 #endif /* defined(TARGET_PPC64) */
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
         break;
     default:
         /* XXX: TODO */
-        cpu_abort(env, "Unknown MMU model\n");
+        cpu_abort(CPU(cpu), "Unknown MMU model\n");
         break;
     }
 }
@@ -1934,6 +1946,9 @@
 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
 {
 #if !defined(FLUSH_ALL_TLBS)
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+    CPUState *cs;
+
     addr &= TARGET_PAGE_MASK;
     switch (env->mmu_model) {
     case POWERPC_MMU_SOFT_6xx:
@@ -1948,43 +1963,44 @@
         ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
         break;
     case POWERPC_MMU_REAL:
-        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+        cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
         break;
     case POWERPC_MMU_MPC8xx:
         /* XXX: TODO */
-        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+        cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
         break;
     case POWERPC_MMU_BOOKE:
         /* XXX: TODO */
-        cpu_abort(env, "BookE MMU model is not implemented\n");
+        cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
         break;
     case POWERPC_MMU_BOOKE206:
         /* XXX: TODO */
-        cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
+        cpu_abort(CPU(cpu), "BookE 2.06 MMU model is not implemented\n");
         break;
     case POWERPC_MMU_32B:
     case POWERPC_MMU_601:
         /* tlbie invalidate TLBs for all segments */
         addr &= ~((target_ulong)-1ULL << 28);
+        cs = CPU(cpu);
         /* XXX: this case should be optimized,
          * giving a mask to tlb_flush_page
          */
-        tlb_flush_page(env, addr | (0x0 << 28));
-        tlb_flush_page(env, addr | (0x1 << 28));
-        tlb_flush_page(env, addr | (0x2 << 28));
-        tlb_flush_page(env, addr | (0x3 << 28));
-        tlb_flush_page(env, addr | (0x4 << 28));
-        tlb_flush_page(env, addr | (0x5 << 28));
-        tlb_flush_page(env, addr | (0x6 << 28));
-        tlb_flush_page(env, addr | (0x7 << 28));
-        tlb_flush_page(env, addr | (0x8 << 28));
-        tlb_flush_page(env, addr | (0x9 << 28));
-        tlb_flush_page(env, addr | (0xA << 28));
-        tlb_flush_page(env, addr | (0xB << 28));
-        tlb_flush_page(env, addr | (0xC << 28));
-        tlb_flush_page(env, addr | (0xD << 28));
-        tlb_flush_page(env, addr | (0xE << 28));
-        tlb_flush_page(env, addr | (0xF << 28));
+        tlb_flush_page(cs, addr | (0x0 << 28));
+        tlb_flush_page(cs, addr | (0x1 << 28));
+        tlb_flush_page(cs, addr | (0x2 << 28));
+        tlb_flush_page(cs, addr | (0x3 << 28));
+        tlb_flush_page(cs, addr | (0x4 << 28));
+        tlb_flush_page(cs, addr | (0x5 << 28));
+        tlb_flush_page(cs, addr | (0x6 << 28));
+        tlb_flush_page(cs, addr | (0x7 << 28));
+        tlb_flush_page(cs, addr | (0x8 << 28));
+        tlb_flush_page(cs, addr | (0x9 << 28));
+        tlb_flush_page(cs, addr | (0xA << 28));
+        tlb_flush_page(cs, addr | (0xB << 28));
+        tlb_flush_page(cs, addr | (0xC << 28));
+        tlb_flush_page(cs, addr | (0xD << 28));
+        tlb_flush_page(cs, addr | (0xE << 28));
+        tlb_flush_page(cs, addr | (0xF << 28));
         break;
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
@@ -1996,12 +2012,12 @@
          *      and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
          *      we just invalidate all TLBs
          */
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
         break;
 #endif /* defined(TARGET_PPC64) */
     default:
         /* XXX: TODO */
-        cpu_abort(env, "Unknown MMU model\n");
+        cpu_abort(CPU(cpu), "Unknown MMU model\n");
         break;
     }
 #else
@@ -2013,6 +2029,8 @@
 /* Special registers manipulation */
 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
     LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
     assert(!env->external_htab);
     if (env->spr[SPR_SDR1] != value) {
@@ -2035,7 +2053,7 @@
             env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
             env->htab_base = value & SDR_32_HTABORG;
         }
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 }
 
@@ -2053,6 +2071,8 @@
 
 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
     LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
             (int)srnum, value, env->sr[srnum]);
 #if defined(TARGET_PPC64)
@@ -2085,11 +2105,11 @@
             page = (16 << 20) * srnum;
             end = page + (16 << 20);
             for (; page != end; page += TARGET_PAGE_SIZE) {
-                tlb_flush_page(env, page);
+                tlb_flush_page(CPU(cpu), page);
             }
         }
 #else
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
 #endif
     }
 }
@@ -2316,6 +2336,8 @@
 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
                          target_ulong val)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
     ppcemb_tlb_t *tlb;
     target_ulong page, end;
 
@@ -2329,7 +2351,7 @@
         LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
                   TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
-            tlb_flush_page(env, page);
+            tlb_flush_page(cs, page);
         }
     }
     tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
@@ -2339,7 +2361,7 @@
      * of the ppc or ppc64 one
      */
     if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
-        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
+        cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
                   "are not supported (%d)\n",
                   tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
     }
@@ -2348,7 +2370,7 @@
         tlb->prot |= PAGE_VALID;
         if (val & PPC4XX_TLBHI_E) {
             /* XXX: TO BE FIXED */
-            cpu_abort(env,
+            cpu_abort(cs,
                       "Little-endian TLB entries are not supported by now\n");
         }
     } else {
@@ -2368,7 +2390,7 @@
         LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
                   TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
-            tlb_flush_page(env, page);
+            tlb_flush_page(cs, page);
         }
     }
 }
@@ -2409,6 +2431,7 @@
 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
                       target_ulong value)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     ppcemb_tlb_t *tlb;
     target_ulong EPN, RPN, size;
     int do_flush_tlbs;
@@ -2444,13 +2467,13 @@
         }
         tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
         if (do_flush_tlbs) {
-            tlb_flush(env, 1);
+            tlb_flush(CPU(cpu), 1);
         }
         break;
     case 1:
         RPN = value & 0xFFFFFC0F;
         if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
-            tlb_flush(env, 1);
+            tlb_flush(CPU(cpu), 1);
         }
         tlb->RPN = RPN;
         break;
@@ -2544,6 +2567,7 @@
 
 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     uint32_t tlbncfg = 0;
     int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
     int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
@@ -2553,7 +2577,7 @@
     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
 
     if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
-        cpu_abort(env, "we don't support HES yet\n");
+        cpu_abort(CPU(cpu), "we don't support HES yet\n");
     }
 
     return booke206_get_tlbm(env, tlb, ea, esel);
@@ -2561,13 +2585,16 @@
 
 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
     env->spr[pidn] = pid;
     /* changing PIDs mean we're in a different address space now */
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 void helper_booke206_tlbwe(CPUPPCState *env)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     uint32_t tlbncfg, tlbn;
     ppcmas_tlb_t *tlb;
     uint32_t size_tlb, size_ps;
@@ -2621,7 +2648,7 @@
     }
 
     if (msr_gs) {
-        cpu_abort(env, "missing HV implementation\n");
+        cpu_abort(CPU(cpu), "missing HV implementation\n");
     }
     tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
         env->spr[SPR_BOOKE_MAS3];
@@ -2655,9 +2682,9 @@
     }
 
     if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
-        tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
+        tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
     } else {
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 }
 
@@ -2764,6 +2791,8 @@
 
 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
     if (address & 0x4) {
         /* flush all entries */
         if (address & 0x8) {
@@ -2779,11 +2808,11 @@
     if (address & 0x8) {
         /* flush TLB1 entries */
         booke206_invalidate_ea_tlb(env, 1, address);
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     } else {
         /* flush TLB0 entries */
         booke206_invalidate_ea_tlb(env, 0, address);
-        tlb_flush_page(env, address & MAS2_EPN_MASK);
+        tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
     }
 }
 
@@ -2795,6 +2824,7 @@
 
 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     int i, j;
     int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
     ppcmas_tlb_t *tlb = env->tlb.tlbm;
@@ -2811,11 +2841,12 @@
         }
         tlb += booke206_tlb_size(env, i);
     }
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     int i, j;
     ppcmas_tlb_t *tlb;
     int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
@@ -2851,7 +2882,7 @@
             tlb->mas1 &= ~MAS1_VALID;
         }
     }
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
@@ -2892,23 +2923,24 @@
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
-    CPUState *cpu = CPU(ppc_env_get_cpu(env));
-    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
+    CPUPPCState *env = &cpu->env;
     int ret;
 
     if (pcc->handle_mmu_fault) {
-        ret = pcc->handle_mmu_fault(env, addr, is_write, mmu_idx);
+        ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
     } else {
         ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     }
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        helper_raise_exception_err(env, env->exception_index, env->error_code);
+        helper_raise_exception_err(env, cs->exception_index, env->error_code);
     }
 }
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 91c33dc..e3fcb03 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -11377,8 +11377,8 @@
     /* Set env in case of segfault during code fetch */
     while (ctx.exception == POWERPC_EXCP_NONE
             && tcg_ctx.gen_opc_ptr < gen_opc_end) {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == ctx.nip) {
                     gen_debug_exception(ctxp);
                     break;
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 3eafbb0..6084f40 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -4432,6 +4432,7 @@
 
 static void init_proc_e500 (CPUPPCState *env, int version)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     uint32_t tlbncfg[2];
     uint64_t ivor_mask;
     uint64_t ivpr_mask = 0xFFFF0000ULL;
@@ -4490,7 +4491,7 @@
         tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
         break;
     default:
-        cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
+        cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
     }
 #endif
     /* Cache sizes */
@@ -4507,7 +4508,7 @@
         l1cfg0 |= 0x1000000; /* 64 byte cache block size */
         break;
     default:
-        cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
+        cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
     }
     gen_spr_BookE206(env, 0x000000DF, tlbncfg);
     /* XXX : not implemented */
@@ -8220,26 +8221,7 @@
 
 PowerPCCPU *cpu_ppc_init(const char *cpu_model)
 {
-    PowerPCCPU *cpu;
-    ObjectClass *oc;
-    Error *err = NULL;
-
-    oc = ppc_cpu_class_by_name(cpu_model);
-    if (oc == NULL) {
-        return NULL;
-    }
-
-    cpu = POWERPC_CPU(object_new(object_class_get_name(oc)));
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", &err);
-    if (err != NULL) {
-        error_report("%s", error_get_pretty(err));
-        error_free(err);
-        object_unref(OBJECT(cpu));
-        return NULL;
-    }
-
-    return cpu;
+    return POWERPC_CPU(cpu_generic_init(TYPE_POWERPC_CPU, cpu_model));
 }
 
 /* Sort by PVR, ordering special case "host" last. */
@@ -8384,6 +8366,14 @@
     cpu->env.nip = value;
 }
 
+static bool ppc_cpu_has_work(CPUState *cs)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
+    return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD);
+}
+
 /* CPUClass::reset() */
 static void ppc_cpu_reset(CPUState *s)
 {
@@ -8433,7 +8423,7 @@
     env->reserve_addr = (target_ulong)-1ULL;
     /* Be sure no exception or interrupt is pending */
     env->pending_interrupts = 0;
-    env->exception_index = POWERPC_EXCP_NONE;
+    s->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 
 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
@@ -8445,7 +8435,7 @@
 #endif /* TARGET_PPC64 */
 
     /* Flush all TLBs */
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 }
 
 static void ppc_cpu_initfn(Object *obj)
@@ -8511,13 +8501,16 @@
     cc->reset = ppc_cpu_reset;
 
     cc->class_by_name = ppc_cpu_class_by_name;
+    cc->has_work = ppc_cpu_has_work;
     cc->do_interrupt = ppc_cpu_do_interrupt;
     cc->dump_state = ppc_cpu_dump_state;
     cc->dump_statistics = ppc_cpu_dump_statistics;
     cc->set_pc = ppc_cpu_set_pc;
     cc->gdb_read_register = ppc_cpu_gdb_read_register;
     cc->gdb_write_register = ppc_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = ppc_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
     cc->vmsd = &vmstate_ppc_cpu;
 #if defined(TARGET_PPC64)
diff --git a/target-ppc/user_only_helper.c b/target-ppc/user_only_helper.c
index 56e686e..829f66f 100644
--- a/target-ppc/user_only_helper.c
+++ b/target-ppc/user_only_helper.c
@@ -20,9 +20,11 @@
 
 #include "cpu.h"
 
-int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
-                         int mmu_idx)
+int ppc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                             int mmu_idx)
 {
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
     int exception, error_code;
 
     if (rw == 2) {
@@ -37,7 +39,7 @@
         env->spr[SPR_DAR] = address;
         env->spr[SPR_DSISR] = error_code;
     }
-    env->exception_index = exception;
+    cs->exception_index = exception;
     env->error_code = error_code;
 
     return 1;
diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c
index a6d60bf..9e676a5 100644
--- a/target-s390x/cc_helper.c
+++ b/target-s390x/cc_helper.c
@@ -407,6 +407,7 @@
 static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
                                   uint64_t src, uint64_t dst, uint64_t vr)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     uint32_t r = 0;
 
     switch (cc_op) {
@@ -524,7 +525,7 @@
         break;
 
     default:
-        cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
+        cpu_abort(CPU(cpu), "Unknown CC operation: %s\n", cc_name(cc_op));
     }
 
     HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
@@ -548,7 +549,7 @@
 void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
 {
     load_psw(env, mask, addr);
-    cpu_loop_exit(env);
+    cpu_loop_exit(CPU(s390_env_get_cpu(env)));
 }
 
 void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 1a8c1cc..dfd83e8 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -65,6 +65,15 @@
     cpu->env.psw.addr = value;
 }
 
+static bool s390_cpu_has_work(CPUState *cs)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+
+    return (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
+           (env->psw.mask & PSW_MASK_EXT);
+}
+
 #if !defined(CONFIG_USER_ONLY)
 /* S390CPUClass::load_normal() */
 static void s390_cpu_load_normal(CPUState *s)
@@ -89,7 +98,7 @@
 #if !defined(CONFIG_USER_ONLY)
     s->halted = 1;
 #endif
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 }
 
 /* S390CPUClass::initial_reset() */
@@ -100,7 +109,7 @@
 
     s390_cpu_reset(s);
     /* initial reset does not touch regs,fregs and aregs */
-    memset(&env->fpc, 0, offsetof(CPUS390XState, breakpoints) -
+    memset(&env->fpc, 0, offsetof(CPUS390XState, cpu_num) -
                          offsetof(CPUS390XState, fpc));
 
     /* architectured initial values for CR 0 and 14 */
@@ -130,7 +139,7 @@
 
     scc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUS390XState, breakpoints));
+    memset(env, 0, offsetof(CPUS390XState, cpu_num));
 
     /* architectured initial values for CR 0 and 14 */
     env->cregs[0] = CR0_RESET;
@@ -144,7 +153,7 @@
 #if !defined(CONFIG_USER_ONLY)
     s->halted = 1;
 #endif
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 }
 
 #if !defined(CONFIG_USER_ONLY)
@@ -232,12 +241,15 @@
     scc->cpu_reset = s390_cpu_reset;
     scc->initial_cpu_reset = s390_cpu_initial_reset;
     cc->reset = s390_cpu_full_reset;
+    cc->has_work = s390_cpu_has_work;
     cc->do_interrupt = s390_cpu_do_interrupt;
     cc->dump_state = s390_cpu_dump_state;
     cc->set_pc = s390_cpu_set_pc;
     cc->gdb_read_register = s390_cpu_gdb_read_register;
     cc->gdb_write_register = s390_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = s390_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
     cc->write_elf64_note = s390_cpu_write_elf64_note;
     cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote;
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index effe84b..f332d41 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -320,9 +320,8 @@
    is returned if the signal was handled by the virtual CPU.  */
 int cpu_s390x_signal_handler(int host_signum, void *pinfo,
                            void *puc);
-int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
-                                int mmu_idx);
-#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
+int s390_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                              int mmu_idx);
 
 #include "ioinst.h"
 
@@ -1041,15 +1040,6 @@
     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    S390CPU *s390_cpu = S390_CPU(cpu);
-    CPUS390XState *env = &s390_cpu->env;
-
-    return (cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
-        (env->psw.mask & PSW_MASK_EXT);
-}
-
 /* fpu_helper.c */
 uint32_t set_cc_nz_f32(float32 v);
 uint32_t set_cc_nz_f64(float64 v);
diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c
index 94375b6..3e9c7b2 100644
--- a/target-s390x/fpu_helper.c
+++ b/target-s390x/fpu_helper.c
@@ -80,6 +80,8 @@
 
 static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
+
     switch (float_compare) {
     case float_relation_equal:
         return 0;
@@ -90,7 +92,7 @@
     case float_relation_unordered:
         return 3;
     default:
-        cpu_abort(env, "unknown return value for float compare\n");
+        cpu_abort(CPU(cpu), "unknown return value for float compare\n");
     }
 }
 
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index aa537e1..aa628b8 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -85,20 +85,19 @@
 
 void s390_cpu_do_interrupt(CPUState *cs)
 {
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-
-    env->exception_index = -1;
+    cs->exception_index = -1;
 }
 
-int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address,
-                               int rw, int mmu_idx)
+int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
+                              int rw, int mmu_idx)
 {
-    env->exception_index = EXCP_PGM;
-    env->int_pgm_code = PGM_ADDRESSING;
+    S390CPU *cpu = S390_CPU(cs);
+
+    cs->exception_index = EXCP_PGM;
+    cpu->env.int_pgm_code = PGM_ADDRESSING;
     /* On real machines this value is dropped into LowMem.  Since this
        is userland, simply put this someplace that cpu_loop can find it.  */
-    env->__excp_addr = address;
+    cpu->env.__excp_addr = address;
     return 1;
 }
 
@@ -108,13 +107,16 @@
 static void trigger_pgm_exception(CPUS390XState *env, uint32_t code,
                                   uint32_t ilen)
 {
-    env->exception_index = EXCP_PGM;
+    CPUState *cs = CPU(s390_env_get_cpu(env));
+
+    cs->exception_index = EXCP_PGM;
     env->int_pgm_code = code;
     env->int_pgm_ilen = ilen;
 }
 
 static int trans_bits(CPUS390XState *env, uint64_t mode)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     int bits = 0;
 
     switch (mode) {
@@ -128,7 +130,7 @@
         bits = 3;
         break;
     default:
-        cpu_abort(env, "unknown asc mode\n");
+        cpu_abort(CPU(cpu), "unknown asc mode\n");
         break;
     }
 
@@ -138,7 +140,7 @@
 static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr,
                                uint64_t mode)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     int ilen = ILEN_LATER_INC;
     int bits = trans_bits(env, mode) | 4;
 
@@ -152,7 +154,7 @@
 static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
                                uint32_t type, uint64_t asc, int rw)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     int ilen = ILEN_LATER;
     int bits = trans_bits(env, asc);
 
@@ -172,7 +174,7 @@
                               uint64_t asc, uint64_t asce, int level,
                               target_ulong *raddr, int *flags, int rw)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     uint64_t offs = 0;
     uint64_t origin;
     uint64_t new_asce;
@@ -379,14 +381,16 @@
     return r;
 }
 
-int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr,
-                               int rw, int mmu_idx)
+int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr,
+                              int rw, int mmu_idx)
 {
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
     target_ulong vaddr, raddr;
     int prot;
 
-    DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n",
+    DPRINTF("%s: address 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
             __func__, orig_vaddr, rw, mmu_idx);
 
     orig_vaddr &= TARGET_PAGE_MASK;
@@ -413,7 +417,7 @@
     DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __func__,
             (uint64_t)vaddr, (uint64_t)raddr, prot);
 
-    tlb_set_page(env, orig_vaddr, raddr, prot,
+    tlb_set_page(cs, orig_vaddr, raddr, prot,
                  mmu_idx, TARGET_PAGE_SIZE);
 
     return 0;
@@ -425,7 +429,7 @@
     CPUS390XState *env = &cpu->env;
     target_ulong raddr;
     int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-    int old_exc = env->exception_index;
+    int old_exc = cs->exception_index;
     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
 
     /* 31-Bit mode */
@@ -434,7 +438,7 @@
     }
 
     mmu_translate(env, vaddr, 2, asc, &raddr, &prot);
-    env->exception_index = old_exc;
+    cs->exception_index = old_exc;
 
     return raddr;
 }
@@ -452,7 +456,7 @@
             }
         }
         cs->halted = 1;
-        env->exception_index = EXCP_HLT;
+        cs->exception_index = EXCP_HLT;
     }
 
     env->psw.addr = addr;
@@ -476,13 +480,14 @@
 
 static LowCore *cpu_map_lowcore(CPUS390XState *env)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     LowCore *lowcore;
     hwaddr len = sizeof(LowCore);
 
     lowcore = cpu_physical_memory_map(env->psa, &len, 1);
 
     if (len < sizeof(LowCore)) {
-        cpu_abort(env, "Could not map lowcore\n");
+        cpu_abort(CPU(cpu), "Could not map lowcore\n");
     }
 
     return lowcore;
@@ -580,16 +585,17 @@
 
 static void do_ext_interrupt(CPUS390XState *env)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     uint64_t mask, addr;
     LowCore *lowcore;
     ExtQueue *q;
 
     if (!(env->psw.mask & PSW_MASK_EXT)) {
-        cpu_abort(env, "Ext int w/o ext mask\n");
+        cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
     }
 
     if (env->ext_index < 0 || env->ext_index > MAX_EXT_QUEUE) {
-        cpu_abort(env, "Ext queue overrun: %d\n", env->ext_index);
+        cpu_abort(CPU(cpu), "Ext queue overrun: %d\n", env->ext_index);
     }
 
     q = &env->ext_queue[env->ext_index];
@@ -619,6 +625,7 @@
 
 static void do_io_interrupt(CPUS390XState *env)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     LowCore *lowcore;
     IOIntQueue *q;
     uint8_t isc;
@@ -626,7 +633,7 @@
     int found = 0;
 
     if (!(env->psw.mask & PSW_MASK_IO)) {
-        cpu_abort(env, "I/O int w/o I/O mask\n");
+        cpu_abort(CPU(cpu), "I/O int w/o I/O mask\n");
     }
 
     for (isc = 0; isc < ARRAY_SIZE(env->io_index); isc++) {
@@ -636,7 +643,7 @@
             continue;
         }
         if (env->io_index[isc] > MAX_IO_QUEUE) {
-            cpu_abort(env, "I/O queue overrun for isc %d: %d\n",
+            cpu_abort(CPU(cpu), "I/O queue overrun for isc %d: %d\n",
                       isc, env->io_index[isc]);
         }
 
@@ -683,24 +690,25 @@
 
 static void do_mchk_interrupt(CPUS390XState *env)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     uint64_t mask, addr;
     LowCore *lowcore;
     MchkQueue *q;
     int i;
 
     if (!(env->psw.mask & PSW_MASK_MCHECK)) {
-        cpu_abort(env, "Machine check w/o mchk mask\n");
+        cpu_abort(CPU(cpu), "Machine check w/o mchk mask\n");
     }
 
     if (env->mchk_index < 0 || env->mchk_index > MAX_MCHK_QUEUE) {
-        cpu_abort(env, "Mchk queue overrun: %d\n", env->mchk_index);
+        cpu_abort(CPU(cpu), "Mchk queue overrun: %d\n", env->mchk_index);
     }
 
     q = &env->mchk_queue[env->mchk_index];
 
     if (q->type != 1) {
         /* Don't know how to handle this... */
-        cpu_abort(env, "Unknown machine check type %d\n", q->type);
+        cpu_abort(CPU(cpu), "Unknown machine check type %d\n", q->type);
     }
     if (!(env->cregs[14] & (1 << 28))) {
         /* CRW machine checks disabled */
@@ -749,43 +757,43 @@
     CPUS390XState *env = &cpu->env;
 
     qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n",
-                  __func__, env->exception_index, env->psw.addr);
+                  __func__, cs->exception_index, env->psw.addr);
 
     s390_add_running_cpu(cpu);
     /* handle machine checks */
     if ((env->psw.mask & PSW_MASK_MCHECK) &&
-        (env->exception_index == -1)) {
+        (cs->exception_index == -1)) {
         if (env->pending_int & INTERRUPT_MCHK) {
-            env->exception_index = EXCP_MCHK;
+            cs->exception_index = EXCP_MCHK;
         }
     }
     /* handle external interrupts */
     if ((env->psw.mask & PSW_MASK_EXT) &&
-        env->exception_index == -1) {
+        cs->exception_index == -1) {
         if (env->pending_int & INTERRUPT_EXT) {
             /* code is already in env */
-            env->exception_index = EXCP_EXT;
+            cs->exception_index = EXCP_EXT;
         } else if (env->pending_int & INTERRUPT_TOD) {
             cpu_inject_ext(cpu, 0x1004, 0, 0);
-            env->exception_index = EXCP_EXT;
+            cs->exception_index = EXCP_EXT;
             env->pending_int &= ~INTERRUPT_EXT;
             env->pending_int &= ~INTERRUPT_TOD;
         } else if (env->pending_int & INTERRUPT_CPUTIMER) {
             cpu_inject_ext(cpu, 0x1005, 0, 0);
-            env->exception_index = EXCP_EXT;
+            cs->exception_index = EXCP_EXT;
             env->pending_int &= ~INTERRUPT_EXT;
             env->pending_int &= ~INTERRUPT_TOD;
         }
     }
     /* handle I/O interrupts */
     if ((env->psw.mask & PSW_MASK_IO) &&
-        (env->exception_index == -1)) {
+        (cs->exception_index == -1)) {
         if (env->pending_int & INTERRUPT_IO) {
-            env->exception_index = EXCP_IO;
+            cs->exception_index = EXCP_IO;
         }
     }
 
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXCP_PGM:
         do_program_interrupt(env);
         break;
@@ -802,7 +810,7 @@
         do_mchk_interrupt(env);
         break;
     }
-    env->exception_index = -1;
+    cs->exception_index = -1;
 
     if (!env->pending_int) {
         cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c
index 85e49aa..6a929ca 100644
--- a/target-s390x/int_helper.c
+++ b/target-s390x/int_helper.c
@@ -106,9 +106,10 @@
             runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
         }
 #else
+        S390CPU *cpu = s390_env_get_cpu(env);
         /* 32-bit hosts would need special wrapper functionality - just abort if
            we encounter such a case; it's very unlikely anyways. */
-        cpu_abort(env, "128 -> 64/64 division not implemented\n");
+        cpu_abort(CPU(cpu), "128 -> 64/64 division not implemented\n");
 #endif
     }
     return ret;
diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index 875ea95..d8ca300 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -44,18 +44,18 @@
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(CPUS390XState *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = s390_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 
@@ -72,6 +72,7 @@
 static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
                             uint8_t byte)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     hwaddr dest_phys;
     hwaddr len = l;
     void *dest_p;
@@ -80,7 +81,7 @@
 
     if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
         cpu_stb_data(env, dest, byte);
-        cpu_abort(env, "should never reach here");
+        cpu_abort(CPU(cpu), "should never reach here");
     }
     dest_phys |= dest & ~TARGET_PAGE_MASK;
 
@@ -94,6 +95,7 @@
 static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
                              uint64_t src)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     hwaddr dest_phys;
     hwaddr src_phys;
     hwaddr len = l;
@@ -104,13 +106,13 @@
 
     if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
         cpu_stb_data(env, dest, 0);
-        cpu_abort(env, "should never reach here");
+        cpu_abort(CPU(cpu), "should never reach here");
     }
     dest_phys |= dest & ~TARGET_PAGE_MASK;
 
     if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
         cpu_ldub_data(env, src);
-        cpu_abort(env, "should never reach here");
+        cpu_abort(CPU(cpu), "should never reach here");
     }
     src_phys |= src & ~TARGET_PAGE_MASK;
 
@@ -483,6 +485,7 @@
 uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
                     uint64_t addr, uint64_t ret)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     uint16_t insn = cpu_lduw_code(env, addr);
 
     HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
@@ -534,7 +537,7 @@
         cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
     } else {
     abort:
-        cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
+        cpu_abort(CPU(cpu), "EXECUTE on instruction prefix 0x%x not implemented\n",
                   insn);
     }
     return cc;
@@ -807,6 +810,7 @@
 #if !defined(CONFIG_USER_ONLY)
 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     int i;
     uint64_t src = a2;
 
@@ -821,11 +825,12 @@
         }
     }
 
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     int i;
     uint64_t src = a2;
 
@@ -839,7 +844,7 @@
         }
     }
 
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
 }
 
 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
@@ -932,6 +937,7 @@
 /* compare and swap and purge */
 uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
     uint32_t cc;
     uint32_t o1 = env->regs[r1];
     uint64_t a2 = r2 & ~3ULL;
@@ -941,7 +947,7 @@
         cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
         if (r2 & 0x3) {
             /* flush TLB / ALB */
-            tlb_flush(env, 1);
+            tlb_flush(CPU(cpu), 1);
         }
         cc = 0;
     } else {
@@ -955,7 +961,7 @@
 static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
                         uint64_t mode1, uint64_t a2, uint64_t mode2)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     target_ulong src, dest;
     int flags, cc = 0, i;
 
@@ -968,12 +974,12 @@
     }
 
     if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
-        cpu_loop_exit(env);
+        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
     }
     dest |= a1 & ~TARGET_PAGE_MASK;
 
     if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
-        cpu_loop_exit(env);
+        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
     }
     src |= a2 & ~TARGET_PAGE_MASK;
 
@@ -1010,7 +1016,7 @@
 /* invalidate pte */
 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     uint64_t page = vaddr & TARGET_PAGE_MASK;
     uint64_t pte = 0;
 
@@ -1024,34 +1030,38 @@
 
     /* XXX we exploit the fact that Linux passes the exact virtual
        address here - it's not obliged to! */
-    tlb_flush_page(env, page);
+    tlb_flush_page(cs, page);
 
     /* XXX 31-bit hack */
     if (page & 0x80000000) {
-        tlb_flush_page(env, page & ~0x80000000);
+        tlb_flush_page(cs, page & ~0x80000000);
     } else {
-        tlb_flush_page(env, page | 0x80000000);
+        tlb_flush_page(cs, page | 0x80000000);
     }
 }
 
 /* flush local tlb */
 void HELPER(ptlb)(CPUS390XState *env)
 {
-    tlb_flush(env, 1);
+    S390CPU *cpu = s390_env_get_cpu(env);
+
+    tlb_flush(CPU(cpu), 1);
 }
 
 /* store using real address */
 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(s390_env_get_cpu(env));
+
     stw_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
 }
 
 /* load real address */
 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
 {
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     uint32_t cc = 0;
-    int old_exc = env->exception_index;
+    int old_exc = cs->exception_index;
     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
     uint64_t ret;
     int flags;
@@ -1061,16 +1071,16 @@
         program_interrupt(env, PGM_SPECIAL_OP, 2);
     }
 
-    env->exception_index = old_exc;
+    cs->exception_index = old_exc;
     if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
         cc = 3;
     }
-    if (env->exception_index == EXCP_PGM) {
+    if (cs->exception_index == EXCP_PGM) {
         ret = env->int_pgm_code | 0x80000000;
     } else {
         ret |= addr & ~TARGET_PAGE_MASK;
     }
-    env->exception_index = old_exc;
+    cs->exception_index = old_exc;
 
     env->cc_op = cc;
     return ret;
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 728456f..294b3ed 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -47,46 +47,53 @@
 void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
                                      uintptr_t retaddr)
 {
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     int t;
 
-    env->exception_index = EXCP_PGM;
+    cs->exception_index = EXCP_PGM;
     env->int_pgm_code = excp;
 
     /* Use the (ultimate) callers address to find the insn that trapped.  */
-    cpu_restore_state(env, retaddr);
+    cpu_restore_state(cs, retaddr);
 
     /* Advance past the insn.  */
     t = cpu_ldub_code(env, env->psw.addr);
     env->int_pgm_ilen = t = get_ilen(t);
     env->psw.addr += 2 * t;
 
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 /* Raise an exception statically from a TB.  */
 void HELPER(exception)(CPUS390XState *env, uint32_t excp)
 {
+    CPUState *cs = CPU(s390_env_get_cpu(env));
+
     HELPER_LOG("%s: exception %d\n", __func__, excp);
-    env->exception_index = excp;
-    cpu_loop_exit(env);
+    cs->exception_index = excp;
+    cpu_loop_exit(cs);
 }
 
 #ifndef CONFIG_USER_ONLY
 
 void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
 {
+    S390CPU *cpu = s390_env_get_cpu(env);
+
     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
                   env->psw.addr);
 
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
-        kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
+        kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code);
 #endif
     } else {
+        CPUState *cs = CPU(cpu);
+
         env->int_pgm_code = code;
         env->int_pgm_ilen = ilen;
-        env->exception_index = EXCP_PGM;
-        cpu_loop_exit(env);
+        cs->exception_index = EXCP_PGM;
+        cpu_loop_exit(cs);
     }
 }
 
@@ -230,11 +237,13 @@
 /* Set Prefix */
 void HELPER(spx)(CPUS390XState *env, uint64_t a1)
 {
+    CPUState *cs = CPU(s390_env_get_cpu(env));
     uint32_t prefix = a1 & 0x7fffe000;
+
     env->psa = prefix;
     qemu_log("prefix: %#x\n", prefix);
-    tlb_flush_page(env, 0);
-    tlb_flush_page(env, TARGET_PAGE_SIZE);
+    tlb_flush_page(cs, 0);
+    tlb_flush_page(cs, TARGET_PAGE_SIZE);
 }
 
 static inline uint64_t clock_value(CPUS390XState *env)
@@ -449,11 +458,11 @@
 #if !defined(CONFIG_USER_ONLY)
     case SIGP_RESTART:
         qemu_system_reset_request();
-        cpu_loop_exit(env);
+        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
         break;
     case SIGP_STOP:
         qemu_system_shutdown_request();
-        cpu_loop_exit(env);
+        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
         break;
 #endif
     default:
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index bc99a37..81b7e33 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -4795,8 +4795,8 @@
         }
 
         status = NO_EXIT;
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == dc.pc) {
                     status = EXIT_PC_STALE;
                     do_debug = true;
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index c23294d..e7f0521 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -39,6 +39,11 @@
     cpu->env.flags = tb->flags;
 }
 
+static bool superh_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
 /* CPUClass::reset() */
 static void superh_cpu_reset(CPUState *s)
 {
@@ -48,8 +53,8 @@
 
     scc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUSH4State, breakpoints));
-    tlb_flush(env, 1);
+    memset(env, 0, offsetof(CPUSH4State, id));
+    tlb_flush(s, 1);
 
     env->pc = 0xA0000000;
 #if defined(CONFIG_USER_ONLY)
@@ -143,18 +148,7 @@
 
 SuperHCPU *cpu_sh4_init(const char *cpu_model)
 {
-    SuperHCPU *cpu;
-    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)));
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return cpu;
+    return SUPERH_CPU(cpu_generic_init(TYPE_SUPERH_CPU, cpu_model));
 }
 
 static void sh7750r_cpu_initfn(Object *obj)
@@ -280,13 +274,16 @@
     cc->reset = superh_cpu_reset;
 
     cc->class_by_name = superh_cpu_class_by_name;
+    cc->has_work = superh_cpu_has_work;
     cc->do_interrupt = superh_cpu_do_interrupt;
     cc->dump_state = superh_cpu_dump_state;
     cc->set_pc = superh_cpu_set_pc;
     cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
     cc->gdb_read_register = superh_cpu_gdb_read_register;
     cc->gdb_write_register = superh_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = superh_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = superh_cpu_get_phys_page_debug;
 #endif
     dc->vmsd = &vmstate_sh_cpu;
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index c181ddac..a2e9e2c 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -175,6 +175,7 @@
 
     CPU_COMMON
 
+    /* Fields from here on are preserved over CPU reset. */
     int id;			/* CPU model */
 
     /* The features that we should emulate. See sh_features above.  */
@@ -193,9 +194,8 @@
 int cpu_sh4_exec(CPUSH4State * s);
 int cpu_sh4_signal_handler(int host_signum, void *pinfo,
                            void *puc);
-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
+int superh_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                                int mmu_idx);
 
 void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 #if !defined(CONFIG_USER_ONLY)
@@ -352,11 +352,6 @@
             | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request & CPU_INTERRUPT_HARD;
-}
-
 #include "exec/exec-all.h"
 
 #endif				/* _CPU_SH4_H */
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index 9ac2825..9ebdd5c 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -33,26 +33,26 @@
 
 void superh_cpu_do_interrupt(CPUState *cs)
 {
+    cs->exception_index = -1;
+}
+
+int superh_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                                int mmu_idx)
+{
     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,
-                             int mmu_idx)
-{
     env->tea = address;
-    env->exception_index = -1;
+    cs->exception_index = -1;
     switch (rw) {
     case 0:
-        env->exception_index = 0x0a0;
+        cs->exception_index = 0x0a0;
         break;
     case 1:
-        env->exception_index = 0x0c0;
+        cs->exception_index = 0x0c0;
         break;
     case 2:
-        env->exception_index = 0x0a0;
+        cs->exception_index = 0x0a0;
         break;
     }
     return 1;
@@ -86,16 +86,16 @@
     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;
+    int do_exp, irq_vector = cs->exception_index;
 
     /* prioritize exceptions over interrupts */
 
-    do_exp = env->exception_index != -1;
-    do_irq = do_irq && (env->exception_index == -1);
+    do_exp = cs->exception_index != -1;
+    do_irq = do_irq && (cs->exception_index == -1);
 
     if (env->sr & SR_BL) {
-        if (do_exp && env->exception_index != 0x1e0) {
-            env->exception_index = 0x000; /* masked exception -> reset */
+        if (do_exp && cs->exception_index != 0x1e0) {
+            cs->exception_index = 0x000; /* masked exception -> reset */
         }
         if (do_irq && !env->in_sleep) {
             return; /* masked */
@@ -113,7 +113,7 @@
 
     if (qemu_loglevel_mask(CPU_LOG_INT)) {
 	const char *expname;
-	switch (env->exception_index) {
+        switch (cs->exception_index) {
 	case 0x0e0:
 	    expname = "addr_error";
 	    break;
@@ -177,8 +177,8 @@
         env->flags = 0;
 
     if (do_exp) {
-        env->expevt = env->exception_index;
-        switch (env->exception_index) {
+        env->expevt = cs->exception_index;
+        switch (cs->exception_index) {
         case 0x000:
         case 0x020:
         case 0x140:
@@ -234,15 +234,21 @@
 
 static int itlb_replacement(CPUSH4State * env)
 {
-    if ((env->mmucr & 0xe0000000) == 0xe0000000)
+    SuperHCPU *cpu = sh_env_get_cpu(env);
+
+    if ((env->mmucr & 0xe0000000) == 0xe0000000) {
 	return 0;
-    if ((env->mmucr & 0x98000000) == 0x18000000)
+    }
+    if ((env->mmucr & 0x98000000) == 0x18000000) {
 	return 1;
-    if ((env->mmucr & 0x54000000) == 0x04000000)
+    }
+    if ((env->mmucr & 0x54000000) == 0x04000000) {
 	return 2;
-    if ((env->mmucr & 0x2c000000) == 0x00000000)
+    }
+    if ((env->mmucr & 0x2c000000) == 0x00000000) {
 	return 3;
-    cpu_abort(env, "Unhandled itlb_replacement");
+    }
+    cpu_abort(CPU(cpu), "Unhandled itlb_replacement");
 }
 
 /* Find the corresponding entry in the right TLB
@@ -298,7 +304,7 @@
     itlb = itlb_replacement(env);
     ientry = &env->itlb[itlb];
     if (ientry->v) {
-        tlb_flush_page(env, ientry->vpn << 10);
+        tlb_flush_page(CPU(sh_env_get_cpu(env)), ientry->vpn << 10);
     }
     *ientry = env->utlb[utlb];
     update_itlb_use(env, itlb);
@@ -447,9 +453,11 @@
     return get_mmu_address(env, physical, prot, address, rw, access_type);
 }
 
-int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
-                             int mmu_idx)
+int superh_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
+                                int mmu_idx)
 {
+    SuperHCPU *cpu = SUPERH_CPU(cs);
+    CPUSH4State *env = &cpu->env;
     target_ulong physical;
     int prot, ret, access_type;
 
@@ -467,36 +475,36 @@
 	switch (ret) {
 	case MMU_ITLB_MISS:
 	case MMU_DTLB_MISS_READ:
-	    env->exception_index = 0x040;
+            cs->exception_index = 0x040;
 	    break;
 	case MMU_DTLB_MULTIPLE:
 	case MMU_ITLB_MULTIPLE:
-	    env->exception_index = 0x140;
+            cs->exception_index = 0x140;
 	    break;
 	case MMU_ITLB_VIOLATION:
-	    env->exception_index = 0x0a0;
+            cs->exception_index = 0x0a0;
 	    break;
 	case MMU_DTLB_MISS_WRITE:
-	    env->exception_index = 0x060;
+            cs->exception_index = 0x060;
 	    break;
 	case MMU_DTLB_INITIAL_WRITE:
-	    env->exception_index = 0x080;
+            cs->exception_index = 0x080;
 	    break;
 	case MMU_DTLB_VIOLATION_READ:
-	    env->exception_index = 0x0a0;
+            cs->exception_index = 0x0a0;
 	    break;
 	case MMU_DTLB_VIOLATION_WRITE:
-	    env->exception_index = 0x0c0;
+            cs->exception_index = 0x0c0;
 	    break;
 	case MMU_IADDR_ERROR:
 	case MMU_DADDR_ERROR_READ:
-	    env->exception_index = 0x0e0;
+            cs->exception_index = 0x0e0;
 	    break;
 	case MMU_DADDR_ERROR_WRITE:
-	    env->exception_index = 0x100;
+            cs->exception_index = 0x100;
 	    break;
 	default:
-            cpu_abort(env, "Unhandled MMU fault");
+            cpu_abort(cs, "Unhandled MMU fault");
 	}
 	return 1;
     }
@@ -504,7 +512,7 @@
     address &= TARGET_PAGE_MASK;
     physical &= TARGET_PAGE_MASK;
 
-    tlb_set_page(env, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
+    tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
     return 0;
 }
 
@@ -520,13 +528,14 @@
 
 void cpu_load_tlb(CPUSH4State * env)
 {
+    SuperHCPU *cpu = sh_env_get_cpu(env);
     int n = cpu_mmucr_urc(env->mmucr);
     tlb_t * entry = &env->utlb[n];
 
     if (entry->v) {
         /* Overwriting valid entry in utlb. */
         target_ulong address = entry->vpn << 10;
-	tlb_flush_page(env, address);
+        tlb_flush_page(CPU(cpu), address);
     }
 
     /* Take values into cpu status from registers. */
@@ -549,7 +558,7 @@
         entry->size = 1024 * 1024; /* 1M */
         break;
     default:
-        cpu_abort(env, "Unhandled load_tlb");
+        cpu_abort(CPU(cpu), "Unhandled load_tlb");
         break;
     }
     entry->sh   = (uint8_t)cpu_ptel_sh(env->ptel);
@@ -576,7 +585,7 @@
         entry->v = 0;
     }
 
-    tlb_flush(s, 1);
+    tlb_flush(CPU(sh_env_get_cpu(s)), 1);
 }
 
 uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
@@ -602,7 +611,7 @@
     if (entry->v) {
         /* Overwriting valid entry in itlb. */
         target_ulong address = entry->vpn << 10;
-        tlb_flush_page(s, address);
+        tlb_flush_page(CPU(sh_env_get_cpu(s)), address);
     }
     entry->asid = asid;
     entry->vpn = vpn;
@@ -644,7 +653,7 @@
         if (entry->v) {
             /* Overwriting valid entry in utlb. */
             target_ulong address = entry->vpn << 10;
-            tlb_flush_page(s, address);
+            tlb_flush_page(CPU(sh_env_get_cpu(s)), address);
         }
         entry->ppn = (mem_value & 0x1ffffc00) >> 10;
         entry->v   = (mem_value & 0x00000100) >> 8;
@@ -697,8 +706,10 @@
             if (entry->vpn == vpn
                 && (!use_asid || entry->asid == asid || entry->sh)) {
 	        if (utlb_match_entry) {
+                    CPUState *cs = CPU(sh_env_get_cpu(s));
+
 		    /* Multiple TLB Exception */
-		    s->exception_index = 0x140;
+                    cs->exception_index = 0x140;
 		    s->tea = addr;
 		    break;
 	        }
@@ -726,16 +737,19 @@
 	    }
 	}
 
-	if (needs_tlb_flush)
-	    tlb_flush_page(s, vpn << 10);
+        if (needs_tlb_flush) {
+            tlb_flush_page(CPU(sh_env_get_cpu(s)), vpn << 10);
+        }
         
     } else {
         int index = (addr & 0x00003f00) >> 8;
         tlb_t * entry = &s->utlb[index];
 	if (entry->v) {
+            CPUState *cs = CPU(sh_env_get_cpu(s));
+
 	    /* Overwriting valid entry in utlb. */
             target_ulong address = entry->vpn << 10;
-	    tlb_flush_page(s, address);
+            tlb_flush_page(cs, address);
 	}
 	entry->asid = asid;
 	entry->vpn = vpn;
@@ -786,7 +800,7 @@
         if (entry->v) {
             /* Overwriting valid entry in utlb. */
             target_ulong address = entry->vpn << 10;
-            tlb_flush_page(s, address);
+            tlb_flush_page(CPU(sh_env_get_cpu(s)), address);
         }
         entry->ppn = (mem_value & 0x1ffffc00) >> 10;
         entry->v   = (mem_value & 0x00000100) >> 8;
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index e955e81..720a97b 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -38,18 +38,18 @@
 #define SHIFT 3
 #include "exec/softmmu_template.h"
 
-void tlb_fill(CPUSH4State *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = superh_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (ret) {
         /* now we have a real cpu fault */
         if (retaddr) {
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 
@@ -58,8 +58,10 @@
 void helper_ldtlb(CPUSH4State *env)
 {
 #ifdef CONFIG_USER_ONLY
+    SuperHCPU *cpu = sh_env_get_cpu(env);
+
     /* XXXXX */
-    cpu_abort(env, "Unhandled ldtlb");
+    cpu_abort(CPU(cpu), "Unhandled ldtlb");
 #else
     cpu_load_tlb(env);
 #endif
@@ -68,11 +70,13 @@
 static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index,
                                                  uintptr_t retaddr)
 {
-    env->exception_index = index;
+    CPUState *cs = CPU(sh_env_get_cpu(env));
+
+    cs->exception_index = index;
     if (retaddr) {
-        cpu_restore_state(env, retaddr);
+        cpu_restore_state(cs, retaddr);
     }
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void helper_raise_illegal_instruction(CPUSH4State *env)
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 661fc6c..2360609 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -1889,8 +1889,8 @@
         max_insns = CF_COUNT_MASK;
     gen_tb_start();
     while (ctx.bstate == BS_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end) {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (ctx.pc == bp->pc) {
 		    /* We have hit a breakpoint - make sure PC is up-to-date */
 		    tcg_gen_movi_i32(cpu_pc, ctx.pc);
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 5806e59..d9f37e9 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -18,6 +18,7 @@
  */
 
 #include "cpu.h"
+#include "qemu/error-report.h"
 
 //#define DEBUG_FEATURES
 
@@ -32,8 +33,8 @@
 
     scc->parent_reset(s);
 
-    memset(env, 0, offsetof(CPUSPARCState, breakpoints));
-    tlb_flush(env, 1);
+    memset(env, 0, offsetof(CPUSPARCState, version));
+    tlb_flush(s, 1);
     env->cwp = 0;
 #ifndef TARGET_SPARC64
     env->wim = 1;
@@ -69,21 +70,32 @@
     env->cache_control = 0;
 }
 
-static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+static int cpu_sparc_register(SPARCCPU *cpu, const char *cpu_model)
 {
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    CPUSPARCState *env = &cpu->env;
+    char *s = g_strdup(cpu_model);
+    char *featurestr, *name = strtok(s, ",");
     sparc_def_t def1, *def = &def1;
+    Error *err = NULL;
 
-    if (cpu_sparc_find_by_name(def, cpu_model) < 0) {
+    if (cpu_sparc_find_by_name(def, name) < 0) {
+        g_free(s);
         return -1;
     }
 
     env->def = g_new0(sparc_def_t, 1);
     memcpy(env->def, def, sizeof(*def));
-#if defined(CONFIG_USER_ONLY)
-    if ((env->def->features & CPU_FEATURE_FLOAT)) {
-        env->def->features |= CPU_FEATURE_FLOAT128;
+
+    featurestr = strtok(NULL, ",");
+    cc->parse_features(CPU(cpu), featurestr, &err);
+    g_free(s);
+    if (err) {
+        error_report("%s", error_get_pretty(err));
+        error_free(err);
+        return -1;
     }
-#endif
+
     env->version = def->iu_version;
     env->fsr = def->fpu_version;
     env->nwindows = def->nwindows;
@@ -103,12 +115,10 @@
 SPARCCPU *cpu_sparc_init(const char *cpu_model)
 {
     SPARCCPU *cpu;
-    CPUSPARCState *env;
 
     cpu = SPARC_CPU(object_new(TYPE_SPARC_CPU));
-    env = &cpu->env;
 
-    if (cpu_sparc_register(env, cpu_model) < 0) {
+    if (cpu_sparc_register(cpu, cpu_model) < 0) {
         object_unref(OBJECT(cpu));
         return NULL;
     }
@@ -506,19 +516,13 @@
             return;
         }
     }
-    fprintf(stderr, "CPU feature %s not found\n", flagname);
+    error_report("CPU feature %s not found", flagname);
 }
 
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *name)
 {
     unsigned int i;
     const sparc_def_t *def = NULL;
-    char *s = g_strdup(cpu_model);
-    char *featurestr, *name = strtok(s, ",");
-    uint32_t plus_features = 0;
-    uint32_t minus_features = 0;
-    uint64_t iu_version;
-    uint32_t fpu_version, mmu_version, nwindows;
 
     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
         if (strcasecmp(name, sparc_defs[i].name) == 0) {
@@ -526,11 +530,24 @@
         }
     }
     if (!def) {
-        goto error;
+        return -1;
     }
     memcpy(cpu_def, def, sizeof(*def));
+    return 0;
+}
 
-    featurestr = strtok(NULL, ",");
+static void sparc_cpu_parse_features(CPUState *cs, char *features,
+                                     Error **errp)
+{
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    sparc_def_t *cpu_def = cpu->env.def;
+    char *featurestr;
+    uint32_t plus_features = 0;
+    uint32_t minus_features = 0;
+    uint64_t iu_version;
+    uint32_t fpu_version, mmu_version, nwindows;
+
+    featurestr = features ? strtok(features, ",") : NULL;
     while (featurestr) {
         char *val;
 
@@ -545,8 +562,8 @@
 
                 iu_version = strtoll(val, &err, 0);
                 if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
+                    error_setg(errp, "bad numerical value %s", val);
+                    return;
                 }
                 cpu_def->iu_version = iu_version;
 #ifdef DEBUG_FEATURES
@@ -557,8 +574,8 @@
 
                 fpu_version = strtol(val, &err, 0);
                 if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
+                    error_setg(errp, "bad numerical value %s", val);
+                    return;
                 }
                 cpu_def->fpu_version = fpu_version;
 #ifdef DEBUG_FEATURES
@@ -569,8 +586,8 @@
 
                 mmu_version = strtol(val, &err, 0);
                 if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
+                    error_setg(errp, "bad numerical value %s", val);
+                    return;
                 }
                 cpu_def->mmu_version = mmu_version;
 #ifdef DEBUG_FEATURES
@@ -582,21 +599,21 @@
                 nwindows = strtol(val, &err, 0);
                 if (!*val || *err || nwindows > MAX_NWINDOWS ||
                     nwindows < MIN_NWINDOWS) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
+                    error_setg(errp, "bad numerical value %s", val);
+                    return;
                 }
                 cpu_def->nwindows = nwindows;
 #ifdef DEBUG_FEATURES
                 fprintf(stderr, "nwindows %d\n", nwindows);
 #endif
             } else {
-                fprintf(stderr, "unrecognized feature %s\n", featurestr);
-                goto error;
+                error_setg(errp, "unrecognized feature %s", featurestr);
+                return;
             }
         } else {
-            fprintf(stderr, "feature string `%s' not in format "
-                    "(+feature|-feature|feature=xyz)\n", featurestr);
-            goto error;
+            error_setg(errp, "feature string `%s' not in format "
+                             "(+feature|-feature|feature=xyz)", featurestr);
+            return;
         }
         featurestr = strtok(NULL, ",");
     }
@@ -605,12 +622,6 @@
 #ifdef DEBUG_FEATURES
     print_features(stderr, fprintf, cpu_def->features, NULL);
 #endif
-    g_free(s);
-    return 0;
-
- error:
-    g_free(s);
-    return -1;
 }
 
 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
@@ -739,9 +750,26 @@
     cpu->env.npc = tb->cs_base;
 }
 
+static bool sparc_cpu_has_work(CPUState *cs)
+{
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
+
+    return (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
+           cpu_interrupts_enabled(env);
+}
+
 static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(dev);
+#if defined(CONFIG_USER_ONLY)
+    SPARCCPU *cpu = SPARC_CPU(dev);
+    CPUSPARCState *env = &cpu->env;
+
+    if ((env->def->features & CPU_FEATURE_FLOAT)) {
+        env->def->features |= CPU_FEATURE_FLOAT128;
+    }
+#endif
 
     qemu_init_vcpu(CPU(dev));
 
@@ -782,6 +810,8 @@
     scc->parent_reset = cc->reset;
     cc->reset = sparc_cpu_reset;
 
+    cc->parse_features = sparc_cpu_parse_features;
+    cc->has_work = sparc_cpu_has_work;
     cc->do_interrupt = sparc_cpu_do_interrupt;
     cc->dump_state = sparc_cpu_dump_state;
 #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
@@ -791,7 +821,9 @@
     cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
     cc->gdb_read_register = sparc_cpu_gdb_read_register;
     cc->gdb_write_register = sparc_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = sparc_cpu_handle_mmu_fault;
+#else
     cc->do_unassigned_access = sparc_cpu_unassigned_access;
     cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
 #endif
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index ed6d2d1..f72451d 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -423,6 +423,7 @@
 
     CPU_COMMON
 
+    /* Fields from here on are preserved across CPU reset. */
     target_ulong version;
     uint32_t nwindows;
 
@@ -521,9 +522,8 @@
 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 /* mmu_helper.c */
-int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
+int sparc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
                                int mmu_idx);
-#define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env);
 
@@ -749,15 +749,6 @@
 #endif
 }
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
-    CPUSPARCState *env1 = &sparc_cpu->env;
-
-    return (cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
-           cpu_interrupts_enabled(env1);
-}
-
 #include "exec/exec-all.h"
 
 #endif
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 57c20af..f3c7fbf 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -24,14 +24,18 @@
 
 void helper_raise_exception(CPUSPARCState *env, int tt)
 {
-    env->exception_index = tt;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+
+    cs->exception_index = tt;
+    cpu_loop_exit(cs);
 }
 
 void helper_debug(CPUSPARCState *env)
 {
-    env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+
+    cs->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(cs);
 }
 
 #ifdef TARGET_SPARC64
@@ -67,6 +71,7 @@
 static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
                                        target_ulong b, int cc)
 {
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
     int overflow = 0;
     uint64_t x0;
     uint32_t x1;
@@ -75,7 +80,7 @@
     x1 = (b & 0xffffffff);
 
     if (x1 == 0) {
-        cpu_restore_state(env, GETPC());
+        cpu_restore_state(CPU(cpu), GETPC());
         helper_raise_exception(env, TT_DIV_ZERO);
     }
 
@@ -106,6 +111,7 @@
 static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
                                        target_ulong b, int cc)
 {
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
     int overflow = 0;
     int64_t x0;
     int32_t x1;
@@ -114,7 +120,7 @@
     x1 = (b & 0xffffffff);
 
     if (x1 == 0) {
-        cpu_restore_state(env, GETPC());
+        cpu_restore_state(CPU(cpu), GETPC());
         helper_raise_exception(env, TT_DIV_ZERO);
     }
 
@@ -147,7 +153,9 @@
 {
     if (b == 0) {
         /* Raise divide by zero trap.  */
-        cpu_restore_state(env, GETPC());
+        SPARCCPU *cpu = sparc_env_get_cpu(env);
+
+        cpu_restore_state(CPU(cpu), GETPC());
         helper_raise_exception(env, TT_DIV_ZERO);
     } else if (b == -1) {
         /* Avoid overflow trap with i386 divide insn.  */
@@ -161,7 +169,9 @@
 {
     if (b == 0) {
         /* Raise divide by zero trap.  */
-        cpu_restore_state(env, GETPC());
+        SPARCCPU *cpu = sparc_env_get_cpu(env);
+
+        cpu_restore_state(CPU(cpu), GETPC());
         helper_raise_exception(env, TT_DIV_ZERO);
     }
     return a / b;
@@ -171,6 +181,7 @@
 target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
                              target_ulong src2)
 {
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
     target_ulong dst;
 
     /* Tag overflow occurs if either input has bits 0 or 1 set.  */
@@ -193,13 +204,14 @@
     return dst;
 
  tag_overflow:
-    cpu_restore_state(env, GETPC());
+    cpu_restore_state(CPU(cpu), GETPC());
     helper_raise_exception(env, TT_TOVF);
 }
 
 target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
                              target_ulong src2)
 {
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
     target_ulong dst;
 
     /* Tag overflow occurs if either input has bits 0 or 1 set.  */
@@ -222,7 +234,7 @@
     return dst;
 
  tag_overflow:
-    cpu_restore_state(env, GETPC());
+    cpu_restore_state(CPU(cpu), GETPC());
     helper_raise_exception(env, TT_TOVF);
 }
 
@@ -232,9 +244,9 @@
     CPUState *cs = CPU(sparc_env_get_cpu(env));
 
     cs->halted = 1;
-    env->exception_index = EXCP_HLT;
+    cs->exception_index = EXCP_HLT;
     env->pc = env->npc;
     env->npc = env->pc + 4;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 #endif
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
index d532238..7c380ba 100644
--- a/target-sparc/int32_helper.c
+++ b/target-sparc/int32_helper.c
@@ -62,7 +62,7 @@
 {
     SPARCCPU *cpu = SPARC_CPU(cs);
     CPUSPARCState *env = &cpu->env;
-    int cwp, intno = env->exception_index;
+    int cwp, intno = cs->exception_index;
 
     /* Compute PSR before exposing state.  */
     if (env->cc_op != CC_OP_FLAGS) {
@@ -105,12 +105,12 @@
 #endif
 #if !defined(CONFIG_USER_ONLY)
     if (env->psret == 0) {
-        if (env->exception_index == 0x80 &&
+        if (cs->exception_index == 0x80 &&
             env->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
             qemu_system_shutdown_request();
         } else {
-            cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
-                      env->exception_index);
+            cpu_abort(cs, "Trap 0x%02x while interrupts disabled, Error state",
+                      cs->exception_index);
         }
         return;
     }
@@ -125,7 +125,7 @@
     env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
     env->pc = env->tbr;
     env->npc = env->pc + 4;
-    env->exception_index = -1;
+    cs->exception_index = -1;
 
 #if !defined(CONFIG_USER_ONLY)
     /* IRQ acknowledgment */
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
index bf7dd86..bf24232 100644
--- a/target-sparc/int64_helper.c
+++ b/target-sparc/int64_helper.c
@@ -63,7 +63,7 @@
 {
     SPARCCPU *cpu = SPARC_CPU(cs);
     CPUSPARCState *env = &cpu->env;
-    int intno = env->exception_index;
+    int intno = cs->exception_index;
     trap_state *tsptr;
 
     /* Compute PSR before exposing state.  */
@@ -111,8 +111,8 @@
 #endif
 #if !defined(CONFIG_USER_ONLY)
     if (env->tl >= env->maxtl) {
-        cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
-                  " Error state", env->exception_index, env->tl, env->maxtl);
+        cpu_abort(cs, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
+                  " Error state", cs->exception_index, env->tl, env->maxtl);
         return;
     }
 #endif
@@ -160,7 +160,7 @@
     env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
     env->pc = env->tbr;
     env->npc = env->pc + 4;
-    env->exception_index = -1;
+    cs->exception_index = -1;
 }
 
 trap_state *cpu_tsptr(CPUSPARCState* env)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 32491b4..ec14802 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -141,6 +141,7 @@
 
     /* flush page range if translation is valid */
     if (TTE_IS_VALID(tlb->tte)) {
+        CPUState *cs = CPU(sparc_env_get_cpu(env1));
 
         mask = 0xffffffffffffe000ULL;
         mask <<= 3 * ((tlb->tte >> 61) & 3);
@@ -149,7 +150,7 @@
         va = tlb->tag & mask;
 
         for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
-            tlb_flush_page(env1, va + offset);
+            tlb_flush_page(cs, va + offset);
         }
     }
 
@@ -447,7 +448,7 @@
 uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
                        int sign)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
     uint64_t ret = 0;
 #if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
     uint32_t last_addr = addr;
@@ -688,8 +689,7 @@
         break;
     case 8: /* User code access, XXX */
     default:
-        cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
-                              addr, false, false, asi, size);
+        cpu_unassigned_access(cs, addr, false, false, asi, size);
         ret = 0;
         break;
     }
@@ -717,7 +717,9 @@
 void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
                    int size)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
     helper_check_align(env, addr, size - 1);
     switch (asi) {
     case 2: /* SuperSparc MXCC registers and Leon3 cache control */
@@ -863,13 +865,13 @@
             DPRINTF_MMU("mmu flush level %d\n", mmulev);
             switch (mmulev) {
             case 0: /* flush page */
-                tlb_flush_page(env, addr & 0xfffff000);
+                tlb_flush_page(CPU(cpu), addr & 0xfffff000);
                 break;
             case 1: /* flush segment (256k) */
             case 2: /* flush region (16M) */
             case 3: /* flush context (4G) */
             case 4: /* flush entire */
-                tlb_flush(env, 1);
+                tlb_flush(CPU(cpu), 1);
                 break;
             default:
                 break;
@@ -894,7 +896,7 @@
                    disabled mode are invalid in normal mode */
                 if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
                     (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) {
-                    tlb_flush(env, 1);
+                    tlb_flush(CPU(cpu), 1);
                 }
                 break;
             case 1: /* Context Table Pointer Register */
@@ -905,7 +907,7 @@
                 if (oldreg != env->mmuregs[reg]) {
                     /* we flush when the MMU context changes because
                        QEMU has no MMU context support */
-                    tlb_flush(env, 1);
+                    tlb_flush(CPU(cpu), 1);
                 }
                 break;
             case 3: /* Synchronous Fault Status Register with Clear */
@@ -1292,7 +1294,7 @@
 uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
                        int sign)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
     uint64_t ret = 0;
 #if defined(DEBUG_ASI)
     target_ulong last_addr = addr;
@@ -1326,7 +1328,7 @@
             dump_asi("read ", last_addr, asi, size, ret);
 #endif
             /* env->exception_index is set in get_physical_address_data(). */
-            helper_raise_exception(env, env->exception_index);
+            helper_raise_exception(env, cs->exception_index);
         }
 
         /* convert nonfaulting load ASIs to normal load ASIs */
@@ -1605,8 +1607,7 @@
     case 0x5f: /* D-MMU demap, WO */
     case 0x77: /* Interrupt vector, WO */
     default:
-        cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
-                              addr, false, false, 1, size);
+        cpu_unassigned_access(cs, addr, false, false, 1, size);
         ret = 0;
         break;
     }
@@ -1662,7 +1663,9 @@
 void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
                    int asi, int size)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
 #ifdef DEBUG_ASI
     dump_asi("write", addr, asi, size, val);
 #endif
@@ -1871,7 +1874,7 @@
 #ifdef DEBUG_MMU
                 dump_mmu(stdout, fprintf, env);
 #endif
-                tlb_flush(env, 1);
+                tlb_flush(CPU(cpu), 1);
             }
             return;
         }
@@ -1960,13 +1963,13 @@
                 env->dmmu.mmu_primary_context = val;
                 /* can be optimized to only flush MMU_USER_IDX
                    and MMU_KERNEL_IDX entries */
-                tlb_flush(env, 1);
+                tlb_flush(CPU(cpu), 1);
                 break;
             case 2: /* Secondary context */
                 env->dmmu.mmu_secondary_context = val;
                 /* can be optimized to only flush MMU_USER_SECONDARY_IDX
                    and MMU_KERNEL_SECONDARY_IDX entries */
-                tlb_flush(env, 1);
+                tlb_flush(CPU(cpu), 1);
                 break;
             case 5: /* TSB access */
                 DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
@@ -2040,8 +2043,7 @@
     case 0x8a: /* Primary no-fault LE, RO */
     case 0x8b: /* Secondary no-fault LE, RO */
     default:
-        cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
-                              addr, true, false, 1, size);
+        cpu_unassigned_access(cs, addr, true, false, 1, size);
         return;
     }
 }
@@ -2397,7 +2399,7 @@
     /* flush neverland mappings created during no-fault mode,
        so the sequential MMU faults report proper fault types */
     if (env->mmuregs[0] & MMU_NF) {
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
     }
 }
 #else
@@ -2427,12 +2429,13 @@
                                               target_ulong addr, int is_write,
                                               int is_user, uintptr_t retaddr)
 {
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
 #ifdef DEBUG_UNALIGNED
     printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
            "\n", addr, env->pc);
 #endif
     if (retaddr) {
-        cpu_restore_state(env, retaddr);
+        cpu_restore_state(CPU(cpu), retaddr);
     }
     helper_raise_exception(env, TT_UNALIGNED);
 }
@@ -2441,17 +2444,17 @@
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(CPUSPARCState *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = sparc_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (ret) {
         if (retaddr) {
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 #endif
diff --git a/target-sparc/machine.c b/target-sparc/machine.c
index a353dab..3f3de4c 100644
--- a/target-sparc/machine.c
+++ b/target-sparc/machine.c
@@ -112,6 +112,7 @@
 int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
     CPUSPARCState *env = opaque;
+    SPARCCPU *cpu = sparc_env_get_cpu(env);
     int i;
     uint32_t tmp;
 
@@ -212,6 +213,6 @@
     qemu_get_be64s(f, &env->ssr);
     cpu_get_timer(f, env->hstick);
 #endif
-    tlb_flush(env, 1);
+    tlb_flush(CPU(cpu), 1);
     return 0;
 }
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
index 5fc2fd6..61afbcf 100644
--- a/target-sparc/mmu_helper.c
+++ b/target-sparc/mmu_helper.c
@@ -25,13 +25,13 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
+int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                                int mmu_idx)
 {
     if (rw & 2) {
-        env1->exception_index = TT_TFAULT;
+        cs->exception_index = TT_TFAULT;
     } else {
-        env1->exception_index = TT_DFAULT;
+        cs->exception_index = TT_DFAULT;
     }
     return 1;
 }
@@ -86,7 +86,7 @@
     uint32_t pde;
     int error_code = 0, is_dirty, is_user;
     unsigned long page_offset;
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
 
     is_user = mmu_idx == MMU_USER_IDX;
 
@@ -198,9 +198,11 @@
 }
 
 /* Perform address translation */
-int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
+int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                                int mmu_idx)
 {
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
     hwaddr paddr;
     target_ulong vaddr;
     target_ulong page_size;
@@ -212,10 +214,10 @@
     vaddr = address;
     if (error_code == 0) {
 #ifdef DEBUG_MMU
-        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
+        printf("Translate at %" VADDR_PRIx " -> " TARGET_FMT_plx ", vaddr "
                TARGET_FMT_lx "\n", address, paddr, vaddr);
 #endif
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
         return 0;
     }
 
@@ -231,13 +233,13 @@
            neverland. Fake/overridden mappings will be flushed when
            switching to normal mode. */
         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
+        tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
         return 0;
     } else {
         if (rw & 2) {
-            env->exception_index = TT_TFAULT;
+            cs->exception_index = TT_TFAULT;
         } else {
-            env->exception_index = TT_DFAULT;
+            cs->exception_index = TT_DFAULT;
         }
         return 1;
     }
@@ -245,7 +247,7 @@
 
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
     hwaddr pde_ptr;
     uint32_t pde;
 
@@ -487,6 +489,7 @@
                                      hwaddr *physical, int *prot,
                                      target_ulong address, int rw, int mmu_idx)
 {
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
     unsigned int i;
     uint64_t context;
     uint64_t sfsr = 0;
@@ -551,10 +554,10 @@
 
             if (do_fault) {
                 /* faults above are reported with TT_DFAULT. */
-                env->exception_index = TT_DFAULT;
+                cs->exception_index = TT_DFAULT;
             } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
                 do_fault = 1;
-                env->exception_index = TT_DPROT;
+                cs->exception_index = TT_DPROT;
 
                 trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
             }
@@ -598,7 +601,7 @@
      * - JPS1: SFAR updated and some fields of SFSR updated
      */
     env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_DMISS;
+    cs->exception_index = TT_DMISS;
     return 1;
 }
 
@@ -606,6 +609,7 @@
                                      hwaddr *physical, int *prot,
                                      target_ulong address, int mmu_idx)
 {
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
     unsigned int i;
     uint64_t context;
 
@@ -649,7 +653,7 @@
 
                 /* FIXME: ASI field in SFSR must be set */
                 env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
-                env->exception_index = TT_TFAULT;
+                cs->exception_index = TT_TFAULT;
 
                 env->immu.tag_access = (address & ~0x1fffULL) | context;
 
@@ -667,7 +671,7 @@
 
     /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
     env->immu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_TMISS;
+    cs->exception_index = TT_TMISS;
     return 1;
 }
 
@@ -705,9 +709,11 @@
 }
 
 /* Perform address translation */
-int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
+int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                                int mmu_idx)
 {
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
     target_ulong vaddr;
     hwaddr paddr;
     target_ulong page_size;
@@ -723,7 +729,7 @@
                                    env->dmmu.mmu_primary_context,
                                    env->dmmu.mmu_secondary_context);
 
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
         return 0;
     }
     /* XXX */
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 46d7859..2de1c4a 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -5270,8 +5270,8 @@
         max_insns = CF_COUNT_MASK;
     gen_tb_start();
     do {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
                     if (dc->pc != pc_start)
                         save_state(dc);
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index 3f78208..2d2c429 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -23,6 +23,12 @@
     cpu->env.regs[31] = value;
 }
 
+static bool uc32_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request &
+        (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
 static inline void set_feature(CPUUniCore32State *env, int feature)
 {
     env->features |= feature;
@@ -115,7 +121,7 @@
     env->regs[31] = 0x03000000;
 #endif
 
-    tlb_flush(env, 1);
+    tlb_flush(cs, 1);
 
     if (tcg_enabled() && !inited) {
         inited = true;
@@ -138,10 +144,13 @@
     dc->realize = uc32_cpu_realizefn;
 
     cc->class_by_name = uc32_cpu_class_by_name;
+    cc->has_work = uc32_cpu_has_work;
     cc->do_interrupt = uc32_cpu_do_interrupt;
     cc->dump_state = uc32_cpu_dump_state;
     cc->set_pc = uc32_cpu_set_pc;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = uc32_cpu_handle_mmu_fault;
+#else
     cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
 #endif
     dc->vmsd = &vmstate_uc32_cpu;
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 967511e..50972f9 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -125,13 +125,10 @@
 #define cpu_init                        uc32_cpu_init
 #define cpu_exec                        uc32_cpu_exec
 #define cpu_signal_handler              uc32_cpu_signal_handler
-#define cpu_handle_mmu_fault            uc32_cpu_handle_mmu_fault
 
 CPUUniCore32State *uc32_cpu_init(const char *cpu_model);
 int uc32_cpu_exec(CPUUniCore32State *s);
 int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
-int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address, int rw,
-                              int mmu_idx);
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
@@ -157,13 +154,9 @@
     }
 }
 
+int uc32_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                              int mmu_idx);
 void uc32_translate_init(void);
 void switch_mode(CPUUniCore32State *, int);
 
-static inline bool cpu_has_work(CPUState *cpu)
-{
-    return cpu->interrupt_request &
-        (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
-}
-
 #endif /* QEMU_UNICORE32_CPU_H */
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 9bf4fea..169c85c 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -28,19 +28,12 @@
 CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
 {
     UniCore32CPU *cpu;
-    CPUUniCore32State *env;
-    ObjectClass *oc;
 
-    oc = cpu_class_by_name(TYPE_UNICORE32_CPU, cpu_model);
-    if (oc == NULL) {
+    cpu = UNICORE32_CPU(cpu_generic_init(TYPE_UNICORE32_CPU, cpu_model));
+    if (cpu == NULL) {
         return NULL;
     }
-    cpu = UNICORE32_CPU(object_new(object_class_get_name(oc)));
-    env = &cpu->env;
-
-    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
-    return env;
+    return &cpu->env;
 }
 
 uint32_t HELPER(clo)(uint32_t x)
@@ -57,6 +50,8 @@
 void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg,
         uint32_t cop)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     /*
      * movc pp.nn, rn, #imm9
      *      rn: UCOP_REG_D
@@ -125,7 +120,7 @@
     case 6:
         if ((cop <= 6) && (cop >= 2)) {
             /* invalid all tlb */
-            tlb_flush(env, 1);
+            tlb_flush(CPU(cpu), 1);
             return;
         }
         break;
@@ -236,23 +231,22 @@
 #ifdef CONFIG_USER_ONLY
 void switch_mode(CPUUniCore32State *env, int mode)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     if (mode != ASR_MODE_USER) {
-        cpu_abort(env, "Tried to switch out of user mode\n");
+        cpu_abort(CPU(cpu), "Tried to switch out of user mode\n");
     }
 }
 
 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");
+    cpu_abort(cs, "NO interrupt in user mode\n");
 }
 
-int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+int uc32_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
                               int access_type, int mmu_idx)
 {
-    cpu_abort(env, "NO mmu fault in user mode\n");
+    cpu_abort(cs, "NO mmu fault in user mode\n");
     return 1;
 }
 #endif
diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c
index 4f9f41e..4c6950d 100644
--- a/target-unicore32/op_helper.c
+++ b/target-unicore32/op_helper.c
@@ -16,8 +16,10 @@
 
 void HELPER(exception)(CPUUniCore32State *env, uint32_t excp)
 {
-    env->exception_index = excp;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(uc32_env_get_cpu(env));
+
+    cs->exception_index = excp;
+    cpu_loop_exit(cs);
 }
 
 static target_ulong asr_read(CPUUniCore32State *env)
@@ -255,18 +257,18 @@
 #define SHIFT 3
 #include "exec/softmmu_template.h"
 
-void tlb_fill(CPUUniCore32State *env, target_ulong addr, int is_write,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write,
               int mmu_idx, uintptr_t retaddr)
 {
     int ret;
 
-    ret = uc32_cpu_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = uc32_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        cpu_loop_exit(env);
+        cpu_loop_exit(cs);
     }
 }
 #endif
diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c
index 22defc6..9a3786d 100644
--- a/target-unicore32/softmmu.c
+++ b/target-unicore32/softmmu.c
@@ -33,6 +33,8 @@
 /* Map CPU modes onto saved register banks.  */
 static inline int bank_number(CPUUniCore32State *env, int mode)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     switch (mode) {
     case ASR_MODE_USER:
     case ASR_MODE_SUSR:
@@ -46,7 +48,7 @@
     case ASR_MODE_INTR:
         return 4;
     }
-    cpu_abort(env, "Bad mode %x\n", mode);
+    cpu_abort(CPU(cpu), "Bad mode %x\n", mode);
     return -1;
 }
 
@@ -79,7 +81,7 @@
     uint32_t addr;
     int new_mode;
 
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case UC32_EXCP_PRIV:
         new_mode = ASR_MODE_PRIV;
         addr = 0x08;
@@ -99,7 +101,7 @@
         addr = 0x18;
         break;
     default:
-        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
         return;
     }
     /* High vectors.  */
@@ -121,7 +123,8 @@
         int access_type, int is_user, uint32_t *phys_ptr, int *prot,
         target_ulong *page_size)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
     int code;
     uint32_t table;
     uint32_t desc;
@@ -168,11 +171,11 @@
             *page_size = TARGET_PAGE_SIZE;
             break;
         default:
-            cpu_abort(env, "wrong page type!");
+            cpu_abort(CPU(cpu), "wrong page type!");
         }
         break;
     default:
-        cpu_abort(env, "wrong page type!");
+        cpu_abort(CPU(cpu), "wrong page type!");
     }
 
     *phys_ptr = phys_addr;
@@ -209,9 +212,11 @@
     return code;
 }
 
-int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+int uc32_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
                               int access_type, int mmu_idx)
 {
+    UniCore32CPU *cpu = UNICORE32_CPU(cs);
+    CPUUniCore32State *env = &cpu->env;
     uint32_t phys_addr;
     target_ulong page_size;
     int prot;
@@ -231,7 +236,7 @@
             ret = get_phys_addr_ucv2(env, address, access_type, is_user,
                                     &phys_addr, &prot, &page_size);
             if (is_user) {
-                DPRINTF("user space access: ret %x, address %x, "
+                DPRINTF("user space access: ret %x, address %" VADDR_PRIx ", "
                         "access_type %x, phys_addr %x, prot %x\n",
                         ret, address, access_type, phys_addr, prot);
             }
@@ -248,16 +253,16 @@
         /* Map a single page.  */
         phys_addr &= TARGET_PAGE_MASK;
         address &= TARGET_PAGE_MASK;
-        tlb_set_page(env, address, phys_addr, prot, mmu_idx, page_size);
+        tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size);
         return 0;
     }
 
     env->cp0.c3_faultstatus = ret;
     env->cp0.c4_faultaddr = address;
     if (access_type == 2) {
-        env->exception_index = UC32_EXCP_ITRAP;
+        cs->exception_index = UC32_EXCP_ITRAP;
     } else {
-        env->exception_index = UC32_EXCP_DTRAP;
+        cs->exception_index = UC32_EXCP_DTRAP;
     }
     return ret;
 }
@@ -266,6 +271,6 @@
 {
     UniCore32CPU *cpu = UNICORE32_CPU(cs);
 
-    cpu_abort(&cpu->env, "%s not supported yet\n", __func__);
+    cpu_abort(CPU(cpu), "%s not supported yet\n", __func__);
     return addr;
 }
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index 4572890..c2402cf 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -176,7 +176,7 @@
 #define UCOP_SET_L              UCOP_SET(24)
 #define UCOP_SET_S              UCOP_SET(24)
 
-#define ILLEGAL         cpu_abort(env,                                  \
+#define ILLEGAL         cpu_abort(CPU(cpu),                             \
                         "Illegal UniCore32 instruction %x at line %d!", \
                         insn, __LINE__)
 
@@ -184,6 +184,7 @@
 static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s,
         uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     TCGv tmp, tmp2, tmp3;
     if ((insn & 0xfe000000) == 0xe0000000) {
         tmp2 = new_tmp();
@@ -209,6 +210,7 @@
 static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s,
         uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     TCGv tmp;
 
     if ((insn & 0xff003fff) == 0xe1000400) {
@@ -689,6 +691,7 @@
 /* UniCore-F64 single load/store I_offset */
 static void do_ucf64_ldst_i(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     int offset;
     TCGv tmp;
     TCGv addr;
@@ -735,6 +738,7 @@
 /* UniCore-F64 load/store multiple words */
 static void do_ucf64_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     unsigned int i;
     int j, n, freg;
     TCGv tmp;
@@ -820,6 +824,7 @@
 /* UniCore-F64 mrc/mcr */
 static void do_ucf64_trans(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     TCGv tmp;
 
     if ((insn & 0xfe0003ff) == 0xe2000000) {
@@ -884,6 +889,8 @@
 /* UniCore-F64 convert instructions */
 static void do_ucf64_fcvt(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     if (UCOP_UCF64_FMT == 3) {
         ILLEGAL;
     }
@@ -950,6 +957,8 @@
 /* UniCore-F64 compare instructions */
 static void do_ucf64_fcmp(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     if (UCOP_SET(25)) {
         ILLEGAL;
     }
@@ -1028,6 +1037,8 @@
 /* UniCore-F64 data processing */
 static void do_ucf64_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     if (UCOP_UCF64_FMT == 3) {
         ILLEGAL;
     }
@@ -1061,6 +1072,8 @@
 /* Disassemble an F64 instruction */
 static void disas_ucf64_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     if (!UCOP_SET(29)) {
         if (UCOP_SET(26)) {
             do_ucf64_ldst_m(env, s, insn);
@@ -1167,6 +1180,8 @@
 static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
         uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
+
     switch (UCOP_CPNUM) {
 #ifndef CONFIG_USER_ONLY
     case 0:
@@ -1181,13 +1196,14 @@
         break;
     default:
         /* Unknown coprocessor. */
-        cpu_abort(env, "Unknown coprocessor!");
+        cpu_abort(CPU(cpu), "Unknown coprocessor!");
     }
 }
 
 /* data processing instructions */
 static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     TCGv tmp;
     TCGv tmp2;
     int logic_cc;
@@ -1421,6 +1437,7 @@
 /* miscellaneous instructions */
 static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     unsigned int val;
     TCGv tmp;
 
@@ -1546,6 +1563,7 @@
 /* SWP instruction */
 static void do_swap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     TCGv addr;
     TCGv tmp;
     TCGv tmp2;
@@ -1573,6 +1591,7 @@
 /* load/store hw/sb */
 static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     TCGv addr;
     TCGv tmp;
 
@@ -1625,6 +1644,7 @@
 /* load/store multiple words */
 static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     unsigned int val, i, mmu_idx;
     int j, n, reg, user, loaded_base;
     TCGv tmp;
@@ -1766,6 +1786,7 @@
 /* branch (and link) */
 static void do_branch(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     unsigned int val;
     int32_t offset;
     TCGv tmp;
@@ -1795,6 +1816,7 @@
 
 static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     unsigned int insn;
 
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
@@ -1922,8 +1944,8 @@
 
     gen_tb_start();
     do {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
                     gen_set_pc_im(dc->pc);
                     gen_exception(EXCP_DEBUG);
@@ -1978,7 +2000,7 @@
         if (dc->condjmp) {
             /* FIXME:  This can theoretically happen with self-modifying
                code.  */
-            cpu_abort(env, "IO on conditional branch instruction");
+            cpu_abort(cs, "IO on conditional branch instruction");
         }
         gen_io_end();
     }
diff --git a/target-unicore32/ucf64_helper.c b/target-unicore32/ucf64_helper.c
index a516edd..34fa2a5 100644
--- a/target-unicore32/ucf64_helper.c
+++ b/target-unicore32/ucf64_helper.c
@@ -76,6 +76,7 @@
 
 void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
 {
+    UniCore32CPU *cpu = uc32_env_get_cpu(env);
     int i;
     uint32_t changed;
 
@@ -99,7 +100,7 @@
             i = float_round_down;
             break;
         default: /* 100 and 101 not implement */
-            cpu_abort(env, "Unsupported UniCore-F64 round mode");
+            cpu_abort(CPU(cpu), "Unsupported UniCore-F64 round mode");
         }
         set_float_rounding_mode(i, &env->ucf64.fp_status);
     }
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index 749e205..6251f1c 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -40,6 +40,13 @@
     cpu->env.pc = value;
 }
 
+static bool xtensa_cpu_has_work(CPUState *cs)
+{
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+
+    return cpu->env.pending_irq_level;
+}
+
 /* CPUClass::reset() */
 static void xtensa_cpu_reset(CPUState *s)
 {
@@ -134,6 +141,7 @@
     cc->reset = xtensa_cpu_reset;
 
     cc->class_by_name = xtensa_cpu_class_by_name;
+    cc->has_work = xtensa_cpu_has_work;
     cc->do_interrupt = xtensa_cpu_do_interrupt;
     cc->dump_state = xtensa_cpu_dump_state;
     cc->set_pc = xtensa_cpu_set_pc;
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 1cf5ea3..e210bac 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -359,7 +359,7 @@
     int exception_taken;
 
     /* Watchpoints for DBREAK registers */
-    CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK];
+    struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK];
 
     CPU_COMMON
 } CPUXtensaState;
@@ -493,6 +493,8 @@
 static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
         target_ulong *cs_base, int *flags)
 {
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
+
     *pc = env->pc;
     *cs_base = 0;
     *flags = 0;
@@ -515,7 +517,7 @@
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) {
         *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT;
     }
-    if (ENV_GET_CPU(env)->singlestep_enabled && env->exception_taken) {
+    if (cs->singlestep_enabled && env->exception_taken) {
         *flags |= XTENSA_TBFLAG_EXCEPTION;
     }
 }
@@ -523,11 +525,4 @@
 #include "exec/cpu-all.h"
 #include "exec/exec-all.h"
 
-static inline int cpu_has_work(CPUState *cpu)
-{
-    CPUXtensaState *env = &XTENSA_CPU(cpu)->env;
-
-    return env->pending_irq_level;
-}
-
 #endif
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 60cb055..94dcd94 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -81,16 +81,18 @@
 
 void xtensa_breakpoint_handler(CPUXtensaState *env)
 {
-    if (env->watchpoint_hit) {
-        if (env->watchpoint_hit->flags & BP_CPU) {
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
+
+    if (cs->watchpoint_hit) {
+        if (cs->watchpoint_hit->flags & BP_CPU) {
             uint32_t cause;
 
-            env->watchpoint_hit = NULL;
+            cs->watchpoint_hit = NULL;
             cause = check_hw_breakpoints(env);
             if (cause) {
                 debug_exception_env(env, cause);
             }
-            cpu_resume_from_signal(env, NULL);
+            cpu_resume_from_signal(cs, NULL);
         }
     }
 }
@@ -169,6 +171,8 @@
             (env->config->level_mask[level] &
              env->sregs[INTSET] &
              env->sregs[INTENABLE])) {
+        CPUState *cs = CPU(xtensa_env_get_cpu(env));
+
         if (level > 1) {
             env->sregs[EPC1 + level - 1] = env->pc;
             env->sregs[EPS2 + level - 2] = env->sregs[PS];
@@ -185,10 +189,10 @@
                 } else {
                     env->sregs[EPC1] = env->pc;
                 }
-                env->exception_index = EXC_DOUBLE;
+                cs->exception_index = EXC_DOUBLE;
             } else {
                 env->sregs[EPC1] = env->pc;
-                env->exception_index =
+                cs->exception_index =
                     (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
             }
             env->sregs[PS] |= PS_EXCM;
@@ -202,7 +206,7 @@
     XtensaCPU *cpu = XTENSA_CPU(cs);
     CPUXtensaState *env = &cpu->env;
 
-    if (env->exception_index == EXC_IRQ) {
+    if (cs->exception_index == EXC_IRQ) {
         qemu_log_mask(CPU_LOG_INT,
                 "%s(EXC_IRQ) level = %d, cintlevel = %d, "
                 "pc = %08x, a0 = %08x, ps = %08x, "
@@ -215,7 +219,7 @@
         handle_interrupt(env);
     }
 
-    switch (env->exception_index) {
+    switch (cs->exception_index) {
     case EXC_WINDOW_OVERFLOW4:
     case EXC_WINDOW_UNDERFLOW4:
     case EXC_WINDOW_OVERFLOW8:
@@ -228,15 +232,15 @@
     case EXC_DEBUG:
         qemu_log_mask(CPU_LOG_INT, "%s(%d) "
                 "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
-                __func__, env->exception_index,
+                __func__, cs->exception_index,
                 env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
-        if (env->config->exception_vector[env->exception_index]) {
+        if (env->config->exception_vector[cs->exception_index]) {
             env->pc = relocated_vector(env,
-                    env->config->exception_vector[env->exception_index]);
+                    env->config->exception_vector[cs->exception_index]);
             env->exception_taken = 1;
         } else {
             qemu_log("%s(pc = %08x) bad exception_index: %d\n",
-                    __func__, env->pc, env->exception_index);
+                    __func__, env->pc, cs->exception_index);
         }
         break;
 
@@ -245,7 +249,7 @@
 
     default:
         qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
-                __func__, env->pc, env->exception_index);
+                __func__, env->pc, cs->exception_index);
         break;
     }
     check_interrupts(env);
@@ -552,7 +556,7 @@
 
 static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
     uint32_t paddr;
     uint32_t page_size;
     unsigned access;
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 509ba49..b531019 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -52,17 +52,21 @@
 static void do_unaligned_access(CPUXtensaState *env,
         target_ulong addr, int is_write, int is_user, uintptr_t retaddr)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
             !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
-        cpu_restore_state(env, retaddr);
+        cpu_restore_state(CPU(cpu), retaddr);
         HELPER(exception_cause_vaddr)(env,
                 env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
     }
 }
 
-void tlb_fill(CPUXtensaState *env,
-        target_ulong vaddr, int is_write, int mmu_idx, uintptr_t retaddr)
+void tlb_fill(CPUState *cs,
+              target_ulong vaddr, int is_write, int mmu_idx, uintptr_t retaddr)
 {
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+    CPUXtensaState *env = &cpu->env;
     uint32_t paddr;
     uint32_t page_size;
     unsigned access;
@@ -73,12 +77,12 @@
             vaddr, is_write, mmu_idx, paddr, ret);
 
     if (ret == 0) {
-        tlb_set_page(env,
-                vaddr & TARGET_PAGE_MASK,
-                paddr & TARGET_PAGE_MASK,
-                access, mmu_idx, page_size);
+        tlb_set_page(cs,
+                     vaddr & TARGET_PAGE_MASK,
+                     paddr & TARGET_PAGE_MASK,
+                     access, mmu_idx, page_size);
     } else {
-        cpu_restore_state(env, retaddr);
+        cpu_restore_state(cs, retaddr);
         HELPER(exception_cause_vaddr)(env, env->pc, ret, vaddr);
     }
 }
@@ -97,11 +101,13 @@
 
 void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
 {
-    env->exception_index = excp;
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
+
+    cs->exception_index = excp;
     if (excp == EXCP_DEBUG) {
         env->exception_taken = 0;
     }
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
@@ -387,7 +393,7 @@
         (intlevel << PS_INTLEVEL_SHIFT);
     check_interrupts(env);
     if (env->pending_irq_level) {
-        cpu_loop_exit(env);
+        cpu_loop_exit(CPU(xtensa_env_get_cpu(env)));
         return;
     }
 
@@ -481,10 +487,12 @@
 
 void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
     v = (v & 0xffffff00) | 0x1;
     if (v != env->sregs[RASID]) {
         env->sregs[RASID] = v;
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 }
 
@@ -681,7 +689,7 @@
         uint32_t wi;
         xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
         if (entry->variable && entry->asid) {
-            tlb_flush_page(env, entry->vaddr);
+            tlb_flush_page(CPU(xtensa_env_get_cpu(env)), entry->vaddr);
             entry->asid = 0;
         }
     }
@@ -726,21 +734,23 @@
 void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
         unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
     xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
 
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
         if (entry->variable) {
             if (entry->asid) {
-                tlb_flush_page(env, entry->vaddr);
+                tlb_flush_page(cs, entry->vaddr);
             }
             xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte);
-            tlb_flush_page(env, entry->vaddr);
+            tlb_flush_page(cs, entry->vaddr);
         } else {
             qemu_log("%s %d, %d, %d trying to set immutable entry\n",
                     __func__, dtlb, wi, ei);
         }
     } else {
-        tlb_flush_page(env, entry->vaddr);
+        tlb_flush_page(cs, entry->vaddr);
         if (xtensa_option_enabled(env->config,
                     XTENSA_OPTION_REGION_TRANSLATION)) {
             entry->paddr = pte & REGION_PAGE_MASK;
@@ -784,11 +794,12 @@
 static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka,
         uint32_t dbreakc)
 {
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
     int flags = BP_CPU | BP_STOP_BEFORE_ACCESS;
     uint32_t mask = dbreakc | ~DBREAKC_MASK;
 
     if (env->cpu_watchpoint[i]) {
-        cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[i]);
+        cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]);
     }
     if (dbreakc & DBREAKC_SB) {
         flags |= BP_MEM_WRITE;
@@ -802,7 +813,7 @@
         /* cut mask after the first zero bit */
         mask = 0xffffffff << (32 - clo32(mask));
     }
-    if (cpu_watchpoint_insert(env, dbreaka & mask, ~mask + 1,
+    if (cpu_watchpoint_insert(cs, dbreaka & mask, ~mask + 1,
             flags, &env->cpu_watchpoint[i])) {
         env->cpu_watchpoint[i] = NULL;
         qemu_log("Failed to set data breakpoint at 0x%08x/%d\n",
@@ -828,7 +839,9 @@
             set_dbreak(env, i, env->sregs[DBREAKA + i], v);
         } else {
             if (env->cpu_watchpoint[i]) {
-                cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[i]);
+                CPUState *cs = CPU(xtensa_env_get_cpu(env));
+
+                cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]);
                 env->cpu_watchpoint[i] = NULL;
             }
         }
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 9f5895e..764cee9 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -2948,10 +2948,11 @@
 
 static void check_breakpoint(CPUXtensaState *env, DisasContext *dc)
 {
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
     CPUBreakpoint *bp;
 
-    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+    if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == dc->pc) {
                 tcg_gen_movi_i32(cpu_pc, dc->pc);
                 gen_exception(dc, EXCP_DEBUG);
diff --git a/translate-all.c b/translate-all.c
index 1ac0246..f243c10 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -197,9 +197,10 @@
 
 /* The cpu state corresponding to 'searched_pc' is restored.
  */
-static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env,
+static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
                                      uintptr_t searched_pc)
 {
+    CPUArchState *env = cpu->env_ptr;
     TCGContext *s = &tcg_ctx;
     int j;
     uintptr_t tc_ptr;
@@ -216,9 +217,9 @@
 
     if (use_icount) {
         /* Reset the cycle counter to the start of the block.  */
-        env->icount_decr.u16.low += tb->icount;
+        cpu->icount_decr.u16.low += tb->icount;
         /* Clear the IO flag.  */
-        env->can_do_io = 0;
+        cpu->can_do_io = 0;
     }
 
     /* find opc index corresponding to search_pc */
@@ -241,7 +242,7 @@
     while (s->gen_opc_instr_start[j] == 0) {
         j--;
     }
-    env->icount_decr.u16.low -= s->gen_opc_icount[j];
+    cpu->icount_decr.u16.low -= s->gen_opc_icount[j];
 
     restore_state_to_opc(env, tb, j);
 
@@ -252,13 +253,13 @@
     return 0;
 }
 
-bool cpu_restore_state(CPUArchState *env, uintptr_t retaddr)
+bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr)
 {
     TranslationBlock *tb;
 
     tb = tb_find_pc(retaddr);
     if (tb) {
-        cpu_restore_state_from_tb(tb, env, retaddr);
+        cpu_restore_state_from_tb(cpu, tb, retaddr);
         return true;
     }
     return false;
@@ -687,7 +688,7 @@
 /* XXX: tb_flush is currently not thread safe */
 void tb_flush(CPUArchState *env1)
 {
-    CPUState *cpu;
+    CPUState *cpu = ENV_GET_CPU(env1);
 
 #if defined(DEBUG_FLUSH)
     printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
@@ -698,14 +699,12 @@
 #endif
     if ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer)
         > tcg_ctx.code_gen_buffer_size) {
-        cpu_abort(env1, "Internal error: code buffer overflow\n");
+        cpu_abort(cpu, "Internal error: code buffer overflow\n");
     }
     tcg_ctx.tb_ctx.nb_tbs = 0;
 
     CPU_FOREACH(cpu) {
-        CPUArchState *env = cpu->env_ptr;
-
-        memset(env->tb_jmp_cache, 0, sizeof(env->tb_jmp_cache));
+        memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache));
     }
 
     memset(tcg_ctx.tb_ctx.tb_phys_hash, 0, sizeof(tcg_ctx.tb_ctx.tb_phys_hash));
@@ -856,10 +855,8 @@
     /* remove the TB from the hash list */
     h = tb_jmp_cache_hash_func(tb->pc);
     CPU_FOREACH(cpu) {
-        CPUArchState *env = cpu->env_ptr;
-
-        if (env->tb_jmp_cache[h] == tb) {
-            env->tb_jmp_cache[h] = NULL;
+        if (cpu->tb_jmp_cache[h] == tb) {
+            cpu->tb_jmp_cache[h] = NULL;
         }
     }
 
@@ -941,10 +938,11 @@
     }
 }
 
-TranslationBlock *tb_gen_code(CPUArchState *env,
+TranslationBlock *tb_gen_code(CPUState *cpu,
                               target_ulong pc, target_ulong cs_base,
                               int flags, int cflags)
 {
+    CPUArchState *env = cpu->env_ptr;
     TranslationBlock *tb;
     uint8_t *tc_ptr;
     tb_page_addr_t phys_pc, phys_page2;
@@ -1009,7 +1007,7 @@
 {
     TranslationBlock *tb, *tb_next, *saved_tb;
     CPUState *cpu = current_cpu;
-#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_HAS_PRECISE_SMC)
     CPUArchState *env = NULL;
 #endif
     tb_page_addr_t tb_start, tb_end;
@@ -1034,7 +1032,7 @@
         /* build code bitmap */
         build_page_bitmap(p);
     }
-#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_HAS_PRECISE_SMC)
     if (cpu != NULL) {
         env = cpu->env_ptr;
     }
@@ -1063,9 +1061,9 @@
             if (current_tb_not_found) {
                 current_tb_not_found = 0;
                 current_tb = NULL;
-                if (env->mem_io_pc) {
+                if (cpu->mem_io_pc) {
                     /* now we have a real cpu fault */
-                    current_tb = tb_find_pc(env->mem_io_pc);
+                    current_tb = tb_find_pc(cpu->mem_io_pc);
                 }
             }
             if (current_tb == tb &&
@@ -1077,7 +1075,7 @@
                 restore the CPU state */
 
                 current_tb_modified = 1;
-                cpu_restore_state_from_tb(current_tb, env, env->mem_io_pc);
+                cpu_restore_state_from_tb(cpu, current_tb, cpu->mem_io_pc);
                 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
                                      &current_flags);
             }
@@ -1104,7 +1102,7 @@
     if (!p->first_tb) {
         invalidate_page_bitmap(p);
         if (is_cpu_write_access) {
-            tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
+            tlb_unprotect_code_phys(cpu, start, cpu->mem_io_vaddr);
         }
     }
 #endif
@@ -1114,8 +1112,8 @@
            modifying the memory. It will ensure that it cannot modify
            itself */
         cpu->current_tb = NULL;
-        tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
-        cpu_resume_from_signal(env, NULL);
+        tb_gen_code(cpu, current_pc, current_cs_base, current_flags, 1);
+        cpu_resume_from_signal(cpu, NULL);
     }
 #endif
 }
@@ -1196,7 +1194,7 @@
                    restore the CPU state */
 
             current_tb_modified = 1;
-            cpu_restore_state_from_tb(current_tb, env, pc);
+            cpu_restore_state_from_tb(cpu, current_tb, pc);
             cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
                                  &current_flags);
         }
@@ -1211,11 +1209,11 @@
            modifying the memory. It will ensure that it cannot modify
            itself */
         cpu->current_tb = NULL;
-        tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
+        tb_gen_code(cpu, current_pc, current_cs_base, current_flags, 1);
         if (locked) {
             mmap_unlock();
         }
-        cpu_resume_from_signal(env, puc);
+        cpu_resume_from_signal(cpu, puc);
     }
 #endif
 }
@@ -1374,16 +1372,16 @@
 }
 #endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */
 
-void tb_check_watchpoint(CPUArchState *env)
+void tb_check_watchpoint(CPUState *cpu)
 {
     TranslationBlock *tb;
 
-    tb = tb_find_pc(env->mem_io_pc);
+    tb = tb_find_pc(cpu->mem_io_pc);
     if (!tb) {
-        cpu_abort(env, "check_watchpoint: could not find TB for pc=%p",
-                  (void *)env->mem_io_pc);
+        cpu_abort(cpu, "check_watchpoint: could not find TB for pc=%p",
+                  (void *)cpu->mem_io_pc);
     }
-    cpu_restore_state_from_tb(tb, env, env->mem_io_pc);
+    cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc);
     tb_phys_invalidate(tb, -1);
 }
 
@@ -1391,7 +1389,6 @@
 /* mask must never be zero, except for A20 change call */
 static void tcg_handle_interrupt(CPUState *cpu, int mask)
 {
-    CPUArchState *env = cpu->env_ptr;
     int old_mask;
 
     old_mask = cpu->interrupt_request;
@@ -1407,10 +1404,10 @@
     }
 
     if (use_icount) {
-        env->icount_decr.u16.high = 0xffff;
-        if (!can_do_io(env)
+        cpu->icount_decr.u16.high = 0xffff;
+        if (!cpu_can_do_io(cpu)
             && (mask & ~old_mask) != 0) {
-            cpu_abort(env, "Raised interrupt while not in I/O function");
+            cpu_abort(cpu, "Raised interrupt while not in I/O function");
         }
     } else {
         cpu->tcg_exit_req = 1;
@@ -1421,8 +1418,11 @@
 
 /* in deterministic execution mode, instructions doing device I/Os
    must be at the end of the TB */
-void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr)
+void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
 {
+#if defined(TARGET_MIPS) || defined(TARGET_SH4)
+    CPUArchState *env = cpu->env_ptr;
+#endif
     TranslationBlock *tb;
     uint32_t n, cflags;
     target_ulong pc, cs_base;
@@ -1430,14 +1430,14 @@
 
     tb = tb_find_pc(retaddr);
     if (!tb) {
-        cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
+        cpu_abort(cpu, "cpu_io_recompile: could not find TB for pc=%p",
                   (void *)retaddr);
     }
-    n = env->icount_decr.u16.low + tb->icount;
-    cpu_restore_state_from_tb(tb, env, retaddr);
+    n = cpu->icount_decr.u16.low + tb->icount;
+    cpu_restore_state_from_tb(cpu, tb, retaddr);
     /* Calculate how many instructions had been executed before the fault
        occurred.  */
-    n = n - env->icount_decr.u16.low;
+    n = n - cpu->icount_decr.u16.low;
     /* Generate a new TB ending on the I/O insn.  */
     n++;
     /* On MIPS and SH, delay slot instructions can only be restarted if
@@ -1447,20 +1447,20 @@
 #if defined(TARGET_MIPS)
     if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
         env->active_tc.PC -= 4;
-        env->icount_decr.u16.low++;
+        cpu->icount_decr.u16.low++;
         env->hflags &= ~MIPS_HFLAG_BMASK;
     }
 #elif defined(TARGET_SH4)
     if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
             && n > 1) {
         env->pc -= 2;
-        env->icount_decr.u16.low++;
+        cpu->icount_decr.u16.low++;
         env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
     }
 #endif
     /* This should never happen.  */
     if (n > CF_COUNT_MASK) {
-        cpu_abort(env, "TB too big during recompile");
+        cpu_abort(cpu, "TB too big during recompile");
     }
 
     cflags = n | CF_LAST_IO;
@@ -1470,27 +1470,27 @@
     tb_phys_invalidate(tb, -1);
     /* FIXME: In theory this could raise an exception.  In practice
        we have already translated the block once so it's probably ok.  */
-    tb_gen_code(env, pc, cs_base, flags, cflags);
+    tb_gen_code(cpu, pc, cs_base, flags, cflags);
     /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
        the first in the TB) then we end up generating a whole new TB and
        repeating the fault, which is horribly inefficient.
        Better would be to execute just this insn uncached, or generate a
        second new TB.  */
-    cpu_resume_from_signal(env, NULL);
+    cpu_resume_from_signal(cpu, NULL);
 }
 
-void tb_flush_jmp_cache(CPUArchState *env, target_ulong addr)
+void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr)
 {
     unsigned int i;
 
     /* Discard jump cache entries for any tb which might potentially
        overlap the flushed page.  */
     i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
-    memset(&env->tb_jmp_cache[i], 0,
+    memset(&cpu->tb_jmp_cache[i], 0,
            TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
 
     i = tb_jmp_cache_hash_page(addr);
-    memset(&env->tb_jmp_cache[i], 0,
+    memset(&cpu->tb_jmp_cache[i], 0,
            TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
 }
 
diff --git a/translate-all.h b/translate-all.h
index f7e5932..02832b2 100644
--- a/translate-all.h
+++ b/translate-all.h
@@ -22,6 +22,6 @@
 /* translate-all.c */
 void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len);
 void cpu_unlink_tb(CPUState *cpu);
-void tb_check_watchpoint(CPUArchState *env);
+void tb_check_watchpoint(CPUState *cpu);
 
 #endif /* TRANSLATE_ALL_H */
diff --git a/user-exec.c b/user-exec.c
index 82bfa66..bc58056 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -38,19 +38,22 @@
 
 //#define DEBUG_SIGNAL
 
-static void exception_action(CPUArchState *env1)
+static void exception_action(CPUState *cpu)
 {
 #if defined(TARGET_I386)
-    raise_exception_err(env1, env1->exception_index, env1->error_code);
+    X86CPU *x86_cpu = X86_CPU(cpu);
+    CPUX86State *env1 = &x86_cpu->env;
+
+    raise_exception_err(env1, cpu->exception_index, env1->error_code);
 #else
-    cpu_loop_exit(env1);
+    cpu_loop_exit(cpu);
 #endif
 }
 
 /* exit the current TB from a signal handler. The host registers are
    restored in a state compatible with the CPU emulator
  */
-void cpu_resume_from_signal(CPUArchState *env1, void *puc)
+void cpu_resume_from_signal(CPUState *cpu, void *puc)
 {
 #ifdef __linux__
     struct ucontext *uc = puc;
@@ -70,8 +73,8 @@
         sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
 #endif
     }
-    env1->exception_index = -1;
-    siglongjmp(env1->jmp_env, 1);
+    cpu->exception_index = -1;
+    siglongjmp(cpu->jmp_env, 1);
 }
 
 /* 'pc' is the host PC at which the exception was raised. 'address' is
@@ -82,7 +85,8 @@
                                     int is_write, sigset_t *old_set,
                                     void *puc)
 {
-    CPUArchState *env;
+    CPUState *cpu;
+    CPUClass *cc;
     int ret;
 
 #if defined(DEBUG_SIGNAL)
@@ -99,9 +103,11 @@
        are still valid segv ones */
     address = h2g_nocheck(address);
 
-    env = current_cpu->env_ptr;
+    cpu = current_cpu;
+    cc = CPU_GET_CLASS(cpu);
     /* see if it is an MMU fault */
-    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX);
+    g_assert(cc->handle_mmu_fault);
+    ret = cc->handle_mmu_fault(cpu, address, is_write, MMU_USER_IDX);
     if (ret < 0) {
         return 0; /* not an MMU fault */
     }
@@ -109,12 +115,12 @@
         return 1; /* the MMU fault was handled without causing real CPU fault */
     }
     /* now we have a real cpu fault */
-    cpu_restore_state(env, pc);
+    cpu_restore_state(cpu, pc);
 
     /* we restore the process signal mask as the sigreturn should
        do it (XXX: use sigsetjmp) */
     sigprocmask(SIG_SETMASK, old_set, NULL);
-    exception_action(env);
+    exception_action(cpu);
 
     /* never comes here */
     return 1;