diff --git a/cpu-exec.c b/cpu-exec.c
index f255ea9..ae6aff9 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -151,7 +151,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
 #endif /* DEBUG_DISAS */
 
     cpu->can_do_io = 0;
-    next_tb = tcg_qemu_tb_exec(env, tb_ptr);
+    next_tb = tcg_qemu_tb_exec((TCGContext *)cpu->tcg_ctx, env, tb_ptr);
     cpu->can_do_io = 1;
     trace_exec_tb_exit((void *) (next_tb & ~TB_EXIT_MASK),
                        next_tb & TB_EXIT_MASK);
@@ -217,14 +217,15 @@ static TranslationBlock *tb_find_slow(CPUState *cpu,
     unsigned int h;
     tb_page_addr_t phys_pc, phys_page1;
     target_ulong virt_page2;
+    TCGContext *tcg_ctx = (TCGContext *)cpu->tcg_ctx;
 
-    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
+    tcg_ctx->tb_ctx.tb_invalidated_flag = 0;
 
     /* find translated block using physical mappings */
     phys_pc = get_page_addr_code(env, pc);
     phys_page1 = phys_pc & TARGET_PAGE_MASK;
     h = tb_phys_hash_func(phys_pc);
-    ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h];
+    ptb1 = &tcg_ctx->tb_ctx.tb_phys_hash[h];
     for(;;) {
         tb = *ptb1;
         if (!tb)
@@ -256,8 +257,8 @@ static TranslationBlock *tb_find_slow(CPUState *cpu,
     /* Move the last found TB to the head of the list */
     if (likely(*ptb1)) {
         *ptb1 = tb->phys_hash_next;
-        tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h];
-        tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
+        tb->phys_hash_next = tcg_ctx->tb_ctx.tb_phys_hash[h];
+        tcg_ctx->tb_ctx.tb_phys_hash[h] = tb;
     }
     /* we add the TB in the virtual pc hash table */
     cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
@@ -306,6 +307,7 @@ int cpu_exec(CPUState *cpu)
     X86CPU *x86_cpu = X86_CPU(cpu);
     CPUArchState *env = (CPUArchState *)cpu->env_ptr;
 #endif
+    TCGContext *tcg_ctx = (TCGContext *)cpu->tcg_ctx;
     int ret, interrupt_request;
     TranslationBlock *tb;
     uint8_t *tc_ptr;
@@ -431,17 +433,17 @@ int cpu_exec(CPUState *cpu)
                     cpu->exception_index = EXCP_INTERRUPT;
                     cpu_loop_exit(cpu);
                 }
-                spin_lock(&tcg_ctx.tb_ctx.tb_lock);
+                spin_lock(&tcg_ctx->tb_ctx.tb_lock);
                 have_tb_lock = true;
                 tb = tb_find_fast(cpu);
                 /* Note: we do it here to avoid a gcc bug on Mac OS X when
                    doing it in tb_find_slow */
-                if (tcg_ctx.tb_ctx.tb_invalidated_flag) {
+                if (tcg_ctx->tb_ctx.tb_invalidated_flag) {
                     /* as some TB could have been invalidated because
                        of memory exceptions while generating the code, we
                        must recompute the hash index here */
                     next_tb = 0;
-                    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
+                    tcg_ctx->tb_ctx.tb_invalidated_flag = 0;
                 }
                 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
                     qemu_log("Trace %p [" TARGET_FMT_lx "] %s\n",
@@ -455,7 +457,7 @@ int cpu_exec(CPUState *cpu)
                                 next_tb & TB_EXIT_MASK, tb);
                 }
                 have_tb_lock = false;
-                spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
+                spin_unlock(&tcg_ctx->tb_ctx.tb_lock);
 
                 /* cpu_interrupt might be called while translating the
                    TB, but before it is linked into a potentially
@@ -524,7 +526,7 @@ int cpu_exec(CPUState *cpu)
             x86_cpu = X86_CPU(cpu);
 #endif
             if (have_tb_lock) {
-                spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
+                spin_unlock(&tcg_ctx->tb_ctx.tb_lock);
                 have_tb_lock = false;
             }
         }
diff --git a/cpus.c b/cpus.c
index 441a026..198a15b 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1353,7 +1353,7 @@ static int tcg_cpu_exec(CPUState *cpu)
         cpu->icount_decr.u16.low = decr;
         cpu->icount_extra = count;
     }
-    ret = cpu_exec(cpu);
+    ret = cpu->cpu_exec(cpu);
 #ifdef CONFIG_PROFILER
     tcg_time += profile_getclock() - ti;
 #endif
@@ -1433,7 +1433,7 @@ void cpu_reload_memory_map(CPUState *cpu)
     /* The CPU and TLB are protected by the iothread lock.  */
     d = atomic_rcu_read(&cpu->as->dispatch);
     cpu->memory_dispatch = d;
-    tlb_flush(cpu, 1);
+    cpu->tlb_flush(cpu, 1);
 }
 #endif
 
diff --git a/cputlb.c b/cputlb.c
index 7606548..bb482d3 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -81,7 +81,7 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
     }
 }
 
-void tlb_flush_page(CPUState *cpu, target_ulong addr)
+void tlb_flush_page(CPUState *cpu, uint64_t addr)
 {
     CPUArchState *env = cpu->env_ptr;
     int i;
@@ -166,27 +166,24 @@ static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
     return ram_addr;
 }
 
-void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length)
+void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length)
 {
-    CPUState *cpu;
     CPUArchState *env;
 
-    CPU_FOREACH(cpu) {
-        int mmu_idx;
+    int mmu_idx;
 
-        env = cpu->env_ptr;
-        for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
-            unsigned int i;
+    env = cpu->env_ptr;
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+        unsigned int i;
 
-            for (i = 0; i < CPU_TLB_SIZE; i++) {
-                tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
-                                      start1, length);
-            }
+        for (i = 0; i < CPU_TLB_SIZE; i++) {
+            tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
+                                  start1, length);
+        }
 
-            for (i = 0; i < CPU_VTLB_SIZE; i++) {
-                tlb_reset_dirty_range(&env->tlb_v_table[mmu_idx][i],
-                                      start1, length);
-            }
+        for (i = 0; i < CPU_VTLB_SIZE; i++) {
+            tlb_reset_dirty_range(&env->tlb_v_table[mmu_idx][i],
+                                  start1, length);
         }
     }
 }
@@ -200,21 +197,22 @@ static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
 
 /* update the TLB corresponding to virtual page vaddr
    so that it is no longer dirty */
-void tlb_set_dirty(CPUArchState *env, target_ulong vaddr)
+void tlb_set_dirty(CPUState *cpu, vaddr addr)
 {
+    CPUArchState *env = cpu->env_ptr;
     int i;
     int mmu_idx;
 
-    vaddr &= TARGET_PAGE_MASK;
-    i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    addr &= TARGET_PAGE_MASK;
+    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
-        tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr);
+        tlb_set_dirty1(&env->tlb_table[mmu_idx][i], addr);
     }
 
     for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
         int k;
         for (k = 0; k < CPU_VTLB_SIZE; k++) {
-            tlb_set_dirty1(&env->tlb_v_table[mmu_idx][k], vaddr);
+            tlb_set_dirty1(&env->tlb_v_table[mmu_idx][k], addr);
         }
     }
 }
diff --git a/exec.c b/exec.c
index 200d18b..05b0a68 100644
--- a/exec.c
+++ b/exec.c
@@ -434,7 +434,7 @@ static int cpu_common_post_load(void *opaque, int version_id)
     /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
        version_id is increased. */
     cpu->interrupt_request &= ~0x01;
-    tlb_flush(cpu, 1);
+    cpu->tlb_flush(cpu, 1);
 
     return 0;
 }
@@ -561,15 +561,15 @@ void cpu_exec_init(CPUState *cpu)
 #if defined(CONFIG_USER_ONLY)
 static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
 {
-    tb_invalidate_phys_page_range(pc, pc + 1, 0);
+    cpu->tb_invalidate_phys_page_range(pc, pc + 1, 0);
 }
 #else
 static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
 {
     hwaddr phys = cpu_get_phys_page_debug(cpu, pc);
     if (phys != -1) {
-        tb_invalidate_phys_addr(cpu->as,
-                                phys | (pc & ~TARGET_PAGE_MASK));
+        cpu->tb_invalidate_phys_addr(cpu->as,
+                                     phys | (pc & ~TARGET_PAGE_MASK));
     }
 }
 #endif
@@ -621,7 +621,7 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
         QTAILQ_INSERT_TAIL(&cpu->watchpoints, wp, entry);
     }
 
-    tlb_flush_page(cpu, addr);
+    cpu->tlb_flush_page(cpu, addr);
 
     if (watchpoint)
         *watchpoint = wp;
@@ -649,7 +649,7 @@ void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint)
 {
     QTAILQ_REMOVE(&cpu->watchpoints, watchpoint, entry);
 
-    tlb_flush_page(cpu, watchpoint->vaddr);
+    cpu->tlb_flush_page(cpu, watchpoint->vaddr);
 
     g_free(watchpoint);
 }
@@ -761,7 +761,7 @@ void cpu_single_step(CPUState *cpu, int enabled)
         } else {
             /* must flush all the translated code to avoid inconsistencies */
             /* XXX: only flush what is necessary */
-            tb_flush(cpu);
+            cpu->tb_flush(cpu);
         }
     }
 }
@@ -840,6 +840,7 @@ found:
 
 static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
 {
+    CPUState *cpu;
     ram_addr_t start1;
     RAMBlock *block;
     ram_addr_t end;
@@ -851,7 +852,9 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
     block = qemu_get_ram_block(start);
     assert(block == qemu_get_ram_block(end - 1));
     start1 = (uintptr_t)ramblock_ptr(block, start - block->offset);
-    cpu_tlb_reset_dirty_all(start1, length);
+    CPU_FOREACH(cpu) {
+        cpu->tlb_reset_dirty(cpu, start1, length);
+    }
     rcu_read_unlock();
 }
 
@@ -1807,7 +1810,7 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
                                uint64_t val, unsigned size)
 {
     if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
-        tb_invalidate_phys_page_fast(ram_addr, size);
+        current_cpu->tb_invalidate_phys_page_fast(ram_addr, size);
     }
     switch (size) {
     case 1:
@@ -1826,8 +1829,7 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
     /* we remove the notdirty callback only if the code has been
        flushed */
     if (!cpu_physical_memory_is_clean(ram_addr)) {
-        CPUArchState *env = current_cpu->env_ptr;
-        tlb_set_dirty(env, current_cpu->mem_io_vaddr);
+        current_cpu->tlb_set_dirty(current_cpu, current_cpu->mem_io_vaddr);
     }
 }
 
@@ -1877,7 +1879,7 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
             wp->hitattrs = attrs;
             if (!cpu->watchpoint_hit) {
                 cpu->watchpoint_hit = wp;
-                tb_check_watchpoint(cpu);
+                cpu->tb_check_watchpoint(cpu);
                 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
                     cpu->exception_index = EXCP_DEBUG;
                     cpu_loop_exit(cpu);
@@ -1885,7 +1887,7 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
 #if 0
 /* FIXME: Virtualise cpu_get_tb_cpu_state */
                     cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
-                    tb_gen_code(cpu, pc, cs_base, cpu_flags, 1);
+                    cpu->tb_gen_code(cpu, pc, cs_base, cpu_flags, 1);
 #endif
                     cpu_resume_from_signal(cpu, NULL);
                 }
@@ -2288,7 +2290,7 @@ static void invalidate_and_set_dirty(hwaddr addr,
                                      hwaddr length)
 {
     if (cpu_physical_memory_range_includes_clean(addr, length)) {
-        tb_invalidate_phys_range(addr, addr + length, 0);
+        current_cpu->tb_invalidate_phys_range(addr, addr + length, 0);
         cpu_physical_memory_set_dirty_range_nocode(addr, length);
     }
     xen_modified_memory(addr, length);
@@ -3041,7 +3043,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
         if (unlikely(in_migration)) {
             if (cpu_physical_memory_is_clean(addr1)) {
                 /* invalidate code */
-                tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
+                current_cpu->tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
                 /* set dirty bit */
                 cpu_physical_memory_set_dirty_range_nocode(addr1, 4);
             }
diff --git a/gdbstub.c b/gdbstub.c
index d37943a..e252b85 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1244,7 +1244,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
             cpu->watchpoint_hit = NULL;
             goto send_packet;
         }
-        tb_flush(cpu);
+        cpu->tb_flush(cpu);
         ret = GDB_SIGNAL_TRAP;
         break;
     case RUN_STATE_PAUSED:
diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h
index 9167ff6..6fc78c9 100644
--- a/include/exec/cputlb.h
+++ b/include/exec/cputlb.h
@@ -26,8 +26,6 @@ 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);
-void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length);
-void tlb_set_dirty(CPUArchState *env, target_ulong vaddr);
 extern int tlb_flush_count;
 
 #endif
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 745cb4a..2314cd6 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -83,35 +83,21 @@ void page_size_init(void);
 
 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(CPUState *env);
 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);
-void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
-                              int is_cpu_write_access);
 #if !defined(CONFIG_USER_ONLY)
 bool qemu_in_vcpu_thread(void);
 void cpu_reload_memory_map(CPUState *cpu);
 void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as);
 /* cputlb.c */
-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 tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
                              hwaddr paddr, MemTxAttrs attrs,
                              int prot, int mmu_idx, target_ulong size);
-void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
 #else
-static inline void tlb_flush_page(CPUState *cpu, target_ulong addr)
-{
-}
-
 static inline void tlb_flush(CPUState *cpu, int flush_global)
 {
 }
@@ -196,7 +182,6 @@ struct TBContext {
 };
 
 void tb_free(TranslationBlock *tb);
-void tb_flush(CPUState *cpu);
 void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
 
 #if defined(USE_DIRECT_JUMP)
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 88fbcfa..79b548a 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -265,7 +265,11 @@ typedef struct PCIHostDeviceAddress {
 
 void tcg_exec_init_add(void (*fn)(unsigned long));
 void tcg_exec_init(unsigned long tb_size);
+
+#if 0
 bool tcg_enabled(void);
+#endif
+#define tcg_enabled() true
 
 void cpu_exec_init_all(void);
 
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 9863db8..a579c18 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -73,6 +73,9 @@ typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr,
 
 struct TranslationBlock;
 
+struct TCGContext;
+extern struct TCGContext *tcg_ctx_ptr;
+
 /**
  * CPUClass:
  * @class_by_name: Callback to map -cpu command line model name to an
@@ -320,8 +323,67 @@ struct CPUState {
        (absolute value) offset as small as possible.  This reduces code
        size, especially for hosts without large memory offsets.  */
     volatile sig_atomic_t tcg_exit_req;
+
+    struct TCGContext *tcg_ctx;
+
+    void (*tlb_flush)(CPUState *cpu, int flush_global);
+    void (*tlb_flush_page)(CPUState *cpu, uint64_t addr);
+    void (*tlb_set_dirty)(CPUState *cpu, vaddr addr);
+    void (*tlb_reset_dirty)(CPUState *cpu, ram_addr_t start, ram_addr_t length);
+
+    void (*tb_check_watchpoint)(CPUState *cpu);
+    void (*tb_flush)(CPUState *cpu);
+    struct TranslationBlock *(*tb_gen_code)(CPUState *cpu, vaddr pc,
+                                            vaddr cs_base,
+                                            int flags, int cflags);
+    void (*tb_invalidate_phys_addr)(AddressSpace *as, hwaddr addr);
+    void (*tb_invalidate_phys_page_range)(tb_page_addr_t start,
+                                          tb_page_addr_t end,
+                                          int is_cpu_write_access);
+    void (*tb_invalidate_phys_page_fast)(tb_page_addr_t start, int len);
+    void (*tb_invalidate_phys_range)(tb_page_addr_t start, tb_page_addr_t end,
+                                     int is_cpu_write_access);
+
+    int (*cpu_exec)(CPUState *cpu);
 };
 
+void tlb_flush(CPUState *cpu, int flush_global);
+void tlb_flush_page(CPUState *cpu, uint64_t addr);
+void tlb_set_dirty(CPUState *cpu, vaddr addr);
+void tlb_reset_dirty(CPUState *cpu, ram_addr_t start, ram_addr_t length);
+
+void tb_check_watchpoint(CPUState *cpu);
+void tb_flush(CPUState *cpu);
+struct TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc, vaddr cs_base,
+                                     int flags, int cflags);
+void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
+void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
+                                   int is_cpu_write_access);
+void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len);
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
+                              int is_cpu_write_access);
+
+int cpu_exec(CPUState *cpu);
+
+#define CPU_SET_QOM_HOOKS(cpu) do {                                         \
+    cpu->tcg_ctx                        = tcg_ctx_ptr;                      \
+                                                                            \
+    cpu->tlb_flush                      = tlb_flush;                        \
+    cpu->tlb_flush_page                 = tlb_flush_page;                   \
+    cpu->tlb_set_dirty                  = tlb_set_dirty;                    \
+    cpu->tlb_reset_dirty                = tlb_reset_dirty;                  \
+                                                                            \
+    cpu->tb_check_watchpoint            = tb_check_watchpoint;              \
+    cpu->tb_flush                       = tb_flush;                         \
+    cpu->tb_gen_code                    = tb_gen_code;                      \
+    cpu->tb_invalidate_phys_addr        = tb_invalidate_phys_addr;          \
+    cpu->tb_invalidate_phys_page_range  = tb_invalidate_phys_page_range;    \
+    cpu->tb_invalidate_phys_page_fast   = tb_invalidate_phys_page_fast;     \
+    cpu->tb_invalidate_phys_range       = tb_invalidate_phys_range;         \
+                                                                            \
+    cpu->cpu_exec                       = cpu_exec;                         \
+} while (0);
+
 QTAILQ_HEAD(CPUTailQ, CPUState);
 extern struct CPUTailQ cpus;
 #define CPU_NEXT(cpu) QTAILQ_NEXT(cpu, node)
diff --git a/qom/cpu.c b/qom/cpu.c
index 108bfa2..605e69c 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -312,6 +312,7 @@ static void cpu_common_initfn(Object *obj)
     CPUState *cpu = CPU(obj);
     CPUClass *cc = CPU_GET_CLASS(obj);
 
+    CPU_SET_QOM_HOOKS(cpu);
     cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
 }
 
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 8beff4c..f01d577 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -6,6 +6,7 @@ stub-obj-y += chr-testdev.o
 stub-obj-y += clock-warp.o
 stub-obj-y += cpu-get-clock.o
 stub-obj-y += cpu-get-icount.o
+stub-obj-y += cpu-qom.o
 stub-obj-y += dump.o
 stub-obj-y += fdset-add-fd.o
 stub-obj-y += fdset-find-fd.o
diff --git a/stubs/cpu-qom.c b/stubs/cpu-qom.c
new file mode 100644
index 0000000..e994f5b
--- /dev/null
+++ b/stubs/cpu-qom.c
@@ -0,0 +1,76 @@
+#include "qom/cpu.h"
+
+static void qom_hook_error(const char *fn_name)
+{
+    fprintf(stderr, "Function %s called from core code. Stub implemention"
+            " called. This function should be called via the CPU qom hook.\n",
+            fn_name);
+    abort();
+}
+
+struct TCGContext *tcg_ctx_ptr;
+
+void tlb_flush(CPUState *cpu, int flush_global)
+{
+    qom_hook_error(__func__);
+}
+
+void tlb_flush_page(CPUState *cpu, uint64_t addr)
+{
+    qom_hook_error(__func__);
+}
+
+void tlb_set_dirty(CPUState *cpu, vaddr addr)
+{
+    qom_hook_error(__func__);
+}
+
+void tlb_reset_dirty(CPUState *cpu, ram_addr_t start, ram_addr_t length)
+{
+    qom_hook_error(__func__);
+}
+
+void tb_check_watchpoint(CPUState *cpu)
+{
+    qom_hook_error(__func__);
+}
+
+void tb_flush(CPUState *cpu)
+{
+    qom_hook_error(__func__);
+}
+
+struct TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc, vaddr cs_base,
+                                     int flags, int cflags)
+{
+    qom_hook_error(__func__);
+    return NULL;
+}
+
+void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
+{
+    qom_hook_error(__func__);
+}
+
+void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
+                                   int is_cpu_write_access)
+{
+    qom_hook_error(__func__);
+}
+
+void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
+{
+    qom_hook_error(__func__);
+}
+
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
+                              int is_cpu_write_access)
+{
+    qom_hook_error(__func__);
+}
+
+int cpu_exec(CPUState *cpu)
+{
+    qom_hook_error(__func__);
+    return 0;
+}
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index d2dfeb4..9068272 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -292,7 +292,6 @@ int cpu_mb_signal_handler(int host_signum, void *pinfo,
 
 #define cpu_init(cpu_model) CPU(cpu_mb_init(cpu_model))
 
-#define cpu_exec cpu_mb_exec
 #define cpu_gen_code cpu_mb_gen_code
 #define cpu_signal_handler cpu_mb_signal_handler
 
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 8b0b696..64c451d 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -930,8 +930,9 @@ static inline unsigned get_mmuidx(TCGMemOpIdx oi)
 #define TB_EXIT_REQUESTED 3
 
 #if !defined(tcg_qemu_tb_exec)
-# define tcg_qemu_tb_exec(env, tb_ptr) \
-    ((uintptr_t (*)(void *, void *))tcg_ctx.code_gen_prologue)(env, tb_ptr)
+# define tcg_qemu_tb_exec(tcg_ctx, env, tb_ptr) \
+    ((uintptr_t (*)(void *, void *)) \
+        (tcg_ctx)->code_gen_prologue)((env), (tb_ptr))
 #endif
 
 void tcg_register_jit(void *buf, size_t buf_size);
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index bd1e974..0987ff3 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -175,7 +175,8 @@ typedef enum {
 
 void tci_disas(uint8_t opc);
 
-uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr);
+uintptr_t tcg_qemu_tb_exec(TCGContext *tcg_ctx, CPUArchState *env,
+                           uint8_t *tb_ptr);
 #define tcg_qemu_tb_exec tcg_qemu_tb_exec
 
 static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
diff --git a/tci.c b/tci.c
index a14717d..ffd5f91 100644
--- a/tci.c
+++ b/tci.c
@@ -466,7 +466,7 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition)
 #endif
 
 /* Interpret pseudo code in tb. */
-uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
+uintptr_t tcg_qemu_tb_exec(TCGContext *tcg_ctx, CPUArchState *env, uint8_t *tb_ptr)
 {
     long tcg_temps[CPU_TEMP_BUF_NLONGS];
     uintptr_t sp_value = (uintptr_t)(tcg_temps + CPU_TEMP_BUF_NLONGS);
diff --git a/translate-all.c b/translate-all.c
index 4854828..d0ec080 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -123,6 +123,7 @@ static void *l1_map[V_L1_SIZE];
 
 /* code generation context */
 TCGContext tcg_ctx;
+TCGContext *tcg_ctx_ptr = &tcg_ctx;
 
 static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
                          tb_page_addr_t phys_page2);
@@ -693,11 +694,6 @@ static __attribute__((constructor)) void register_tcg_exec_init(void)
     tcg_exec_init_add(do_tcg_exec_init);
 }
 
-bool tcg_enabled(void)
-{
-    return tcg_ctx.code_gen_buffer != NULL;
-}
-
 /* Allocate a new translation block. Flush the translation buffer if
    too many translation blocks or too much generated code. */
 static TranslationBlock *tb_alloc(target_ulong pc)
@@ -994,8 +990,7 @@ static void build_page_bitmap(PageDesc *p)
     }
 }
 
-TranslationBlock *tb_gen_code(CPUState *cpu,
-                              target_ulong pc, target_ulong cs_base,
+TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc, vaddr cs_base,
                               int flags, int cflags)
 {
     CPUArchState *env = cpu->env_ptr;
diff --git a/translate-all.h b/translate-all.h
index 02832b2..7c079fd 100644
--- a/translate-all.h
+++ b/translate-all.h
@@ -20,8 +20,6 @@
 #define TRANSLATE_ALL_H
 
 /* 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(CPUState *cpu);
 
 #endif /* TRANSLATE_ALL_H */
