cpu: Replace do_interrupt() by CPUClass::do_interrupt method

This removes a global per-target function and thus takes us one step
closer to compiling multiple targets into one executable.

It will also allow to override the interrupt handling for certain CPU
families.

Signed-off-by: Andreas Färber <afaerber@suse.de>
diff --git a/cpu-exec.c b/cpu-exec.c
index c9e1a82..94fedc5 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -198,6 +198,10 @@
 int cpu_exec(CPUArchState *env)
 {
     CPUState *cpu = ENV_GET_CPU(env);
+#if !(defined(CONFIG_USER_ONLY) && \
+      (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+#endif
     int ret, interrupt_request;
     TranslationBlock *tb;
     uint8_t *tc_ptr;
@@ -265,12 +269,12 @@
                        which will be handled outside the cpu execution
                        loop */
 #if defined(TARGET_I386)
-                    do_interrupt(env);
+                    cc->do_interrupt(cpu);
 #endif
                     ret = env->exception_index;
                     break;
 #else
-                    do_interrupt(env);
+                    cc->do_interrupt(cpu);
                     env->exception_index = -1;
 #endif
                 }
@@ -380,7 +384,7 @@
                     if ((interrupt_request & CPU_INTERRUPT_HARD)
                         && (env->ie & IE_IE)) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_MICROBLAZE)
@@ -389,7 +393,7 @@
                         && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
                         && !(env->iflags & (D_FLAG | IMM_FLAG))) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_MIPS)
@@ -398,7 +402,7 @@
                         /* Raise it */
                         env->exception_index = EXCP_EXT_INTERRUPT;
                         env->error_code = 0;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_OPENRISC)
@@ -414,7 +418,7 @@
                         }
                         if (idx >= 0) {
                             env->exception_index = idx;
-                            do_interrupt(env);
+                            cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
                     }
@@ -429,7 +433,7 @@
                                   cpu_pil_allowed(env, pil)) ||
                                   type != TT_EXTINT) {
                                 env->exception_index = env->interrupt_index;
-                                do_interrupt(env);
+                                cc->do_interrupt(cpu);
                                 next_tb = 0;
                             }
                         }
@@ -438,7 +442,7 @@
                     if (interrupt_request & CPU_INTERRUPT_FIQ
                         && !(env->uncached_cpsr & CPSR_F)) {
                         env->exception_index = EXCP_FIQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
                     /* ARMv7-M interrupt return works by loading a magic value
@@ -454,19 +458,19 @@
                         && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                             || !(env->uncached_cpsr & CPSR_I))) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_UNICORE32)
                     if (interrupt_request & CPU_INTERRUPT_HARD
                         && !(env->uncached_asr & ASR_I)) {
                         env->exception_index = UC32_EXCP_INTR;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_SH4)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_ALPHA)
@@ -497,7 +501,7 @@
                         if (idx >= 0) {
                             env->exception_index = idx;
                             env->error_code = 0;
-                            do_interrupt(env);
+                            cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
                     }
@@ -506,7 +510,7 @@
                         && (env->pregs[PR_CCS] & I_FLAG)
                         && !env->locked_irq) {
                         env->exception_index = EXCP_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
                     if (interrupt_request & CPU_INTERRUPT_NMI) {
@@ -518,7 +522,7 @@
                         }
                         if ((env->pregs[PR_CCS] & m_flag_archval)) {
                             env->exception_index = EXCP_NMI;
-                            do_interrupt(env);
+                            cc->do_interrupt(cpu);
                             next_tb = 0;
                         }
                     }
@@ -538,13 +542,13 @@
 #elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                         (env->psw.mask & PSW_MASK_EXT)) {
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #elif defined(TARGET_XTENSA)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
                         env->exception_index = EXC_IRQ;
-                        do_interrupt(env);
+                        cc->do_interrupt(cpu);
                         next_tb = 0;
                     }
 #endif
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 2e08135..3664a1b 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -44,6 +44,7 @@
  * @class_by_name: Callback to map -cpu command line model name to an
  * instantiatable CPU type.
  * @reset: Callback to reset the #CPUState to its initial state.
+ * @do_interrupt: Callback for interrupt handling.
  * @vmsd: State description for migration.
  *
  * Represents a CPU family or model.
@@ -56,6 +57,7 @@
     ObjectClass *(*class_by_name)(const char *cpu_model);
 
     void (*reset)(CPUState *cpu);
+    void (*do_interrupt)(CPUState *cpu);
 
     const struct VMStateDescription *vmsd;
 } CPUClass;
diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h
index 252bd14..32ee286 100644
--- a/target-alpha/cpu-qom.h
+++ b/target-alpha/cpu-qom.h
@@ -74,4 +74,6 @@
 
 #define ENV_OFFSET offsetof(AlphaCPU, env)
 
+void alpha_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index cec9989..cad1716 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -263,6 +263,7 @@
     dc->realize = alpha_cpu_realizefn;
 
     cc->class_by_name = alpha_cpu_class_by_name;
+    cc->do_interrupt = alpha_cpu_do_interrupt;
 }
 
 static const TypeInfo alpha_cpu_type_info = {
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 90f78ac..2156a1e 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -449,7 +449,6 @@
 int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, uint64_t address, int rw,
                                 int mmu_idx);
 #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
-void do_interrupt (CPUAlphaState *env);
 void do_restore_state(CPUAlphaState *, uintptr_t retaddr);
 void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int);
 void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t);
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 22c9c6e..5741ec2 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -345,8 +345,10 @@
 }
 #endif /* USER_ONLY */
 
-void do_interrupt (CPUAlphaState *env)
+void alpha_cpu_do_interrupt(CPUState *cs)
 {
+    AlphaCPU *cpu = ALPHA_CPU(cs);
+    CPUAlphaState *env = &cpu->env;
     int i = env->exception_index;
 
     if (qemu_loglevel_mask(CPU_LOG_INT)) {
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7539727..eeecc92 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -113,4 +113,6 @@
 
 void register_cp_regs_for_features(ARMCPU *cpu);
 
+void arm_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 5dfcb74..aeaa3b7 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -802,6 +802,7 @@
     cc->reset = arm_cpu_reset;
 
     cc->class_by_name = arm_cpu_class_by_name;
+    cc->do_interrupt = arm_cpu_do_interrupt;
 }
 
 static void cpu_register(const ARMCPUInfo *info)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 957866c..2b97221 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -236,7 +236,6 @@
 void arm_translate_init(void);
 void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
 int cpu_arm_exec(CPUARMState *s);
-void do_interrupt(CPUARMState *);
 int bank_number(int mode);
 void switch_mode(CPUARMState *, int);
 uint32_t do_arm_semihosting(CPUARMState *env);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index f839726..b4cbb87 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1567,8 +1567,11 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUARMState *env)
+void arm_cpu_do_interrupt(CPUState *cs)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
     env->exception_index = -1;
 }
 
@@ -1799,9 +1802,10 @@
 }
 
 /* Handle a CPU exception.  */
-void do_interrupt(CPUARMState *env)
+void arm_cpu_do_interrupt(CPUState *cs)
 {
-    CPUState *cs;
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
     uint32_t addr;
     uint32_t mask;
     int new_mode;
@@ -1908,7 +1912,6 @@
     }
     env->regs[14] = env->regs[15] + offset;
     env->regs[15] = addr;
-    cs = CPU(arm_env_get_cpu(env));
     cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 
diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h
index 11e5286..deea1d8 100644
--- a/target-cris/cpu-qom.h
+++ b/target-cris/cpu-qom.h
@@ -73,4 +73,6 @@
 
 #define ENV_OFFSET offsetof(CRISCPU, env)
 
+void cris_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 7974be3..95cbf39 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -243,6 +243,7 @@
     cc->reset = cris_cpu_reset;
 
     cc->class_by_name = cris_cpu_class_by_name;
+    cc->do_interrupt = cris_cpu_do_interrupt;
 }
 
 static const TypeInfo cris_cpu_type_info = {
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 2fc7c5c..dbd7d36 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -175,7 +175,6 @@
 
 CRISCPU *cpu_cris_init(const char *cpu_model);
 int cpu_cris_exec(CPUCRISState *s);
-void do_interrupt(CPUCRISState *env);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
diff --git a/target-cris/helper.c b/target-cris/helper.c
index 885f67f..e1ef7bc 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -36,8 +36,11 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt(CPUCRISState *env)
+void cris_cpu_do_interrupt(CPUState *cs)
 {
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
+
     env->exception_index = -1;
     env->pregs[PR_ERP] = env->pc;
 }
@@ -162,9 +165,10 @@
                   env->pregs[PR_ERP]);
 }
 
-void do_interrupt(CPUCRISState *env)
+void cris_cpu_do_interrupt(CPUState *cs)
 {
-    D(CPUState *cs = CPU(cris_env_get_cpu(env)));
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
     int ex_vec = -1;
 
     if (env->pregs[PR_VR] < 32) {
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 83c5318..08f9eb6 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -80,4 +80,10 @@
 extern const struct VMStateDescription vmstate_x86_cpu;
 #endif
 
+/**
+ * x86_cpu_do_interrupt:
+ * @cpu: vCPU the interrupt is to be handled by.
+ */
+void x86_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 2bdbf1b..a0640db 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2251,6 +2251,7 @@
     xcc->parent_reset = cc->reset;
     cc->reset = x86_cpu_reset;
 
+    cc->do_interrupt = x86_cpu_do_interrupt;
     cpu_class_set_vmsd(cc, &vmstate_x86_cpu);
 }
 
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index bf6e210..48f41ca 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1252,8 +1252,7 @@
                                    uint64_t param);
 void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1);
 
-/* op_helper.c */
-void do_interrupt(CPUX86State *env);
+/* seg_helper.c */
 void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
 
 void do_smm_enter(CPUX86State *env1);
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 3247dee..906e4f3 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -1231,8 +1231,11 @@
 #endif
 }
 
-void do_interrupt(CPUX86State *env)
+void x86_cpu_do_interrupt(CPUState *cs)
 {
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
 #if defined(CONFIG_USER_ONLY)
     /* if user mode only, we simulate a fake exception
        which will be handled outside the cpu execution
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
index c0b6ce5..3ba86b7 100644
--- a/target-lm32/cpu-qom.h
+++ b/target-lm32/cpu-qom.h
@@ -71,4 +71,6 @@
 
 #define ENV_OFFSET offsetof(LM32CPU, env)
 
+void lm32_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index a2badb5..a4692b7 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -83,6 +83,8 @@
 
     lcc->parent_reset = cc->reset;
     cc->reset = lm32_cpu_reset;
+
+    cc->do_interrupt = lm32_cpu_do_interrupt;
 }
 
 static const TypeInfo lm32_cpu_type_info = {
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index d81f103..1be9778 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -189,7 +189,6 @@
 LM32CPU *cpu_lm32_init(const char *cpu_model);
 void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf);
 int cpu_lm32_exec(CPULM32State *s);
-void do_interrupt(CPULM32State *env);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 47ae7e7..a0a8399 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -42,8 +42,11 @@
     return addr & TARGET_PAGE_MASK;
 }
 
-void do_interrupt(CPULM32State *env)
+void lm32_cpu_do_interrupt(CPUState *cs)
 {
+    LM32CPU *cpu = LM32_CPU(cs);
+    CPULM32State *env = &cpu->env;
+
     qemu_log_mask(CPU_LOG_INT,
             "exception at pc=%x type=%x\n", env->pc, env->exception_index);
 
diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h
index f4c33b2..846aa74 100644
--- a/target-m68k/cpu-qom.h
+++ b/target-m68k/cpu-qom.h
@@ -70,4 +70,6 @@
 
 #define ENV_OFFSET offsetof(M68kCPU, env)
 
+void m68k_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c
index f5a1098..3c65b4e 100644
--- a/target-m68k/cpu.c
+++ b/target-m68k/cpu.c
@@ -186,6 +186,7 @@
     cc->reset = m68k_cpu_reset;
 
     cc->class_by_name = m68k_cpu_class_by_name;
+    cc->do_interrupt = m68k_cpu_do_interrupt;
     dc->vmsd = &vmstate_m68k_cpu;
 }
 
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index bb2fbd6..c90c40c 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -119,7 +119,6 @@
 void m68k_cpu_init_gdb(M68kCPU *cpu);
 M68kCPU *cpu_m68k_init(const char *cpu_model);
 int cpu_m68k_exec(CPUM68KState *s);
-void do_interrupt(CPUM68KState *env1);
 void do_interrupt_m68k_hardirq(CPUM68KState *env1);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index e11f34b..30f7d8b 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -21,8 +21,11 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt(CPUM68KState *env)
+void m68k_cpu_do_interrupt(CPUState *cs)
 {
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
     env->exception_index = -1;
 }
 
@@ -149,8 +152,11 @@
     env->pc = cpu_ldl_kernel(env, env->vbr + vector);
 }
 
-void do_interrupt(CPUM68KState *env)
+void m68k_cpu_do_interrupt(CPUState *cs)
 {
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
     do_interrupt_all(env, 0);
 }
 
diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h
index a0248a5..aa51cf6 100644
--- a/target-microblaze/cpu-qom.h
+++ b/target-microblaze/cpu-qom.h
@@ -70,4 +70,6 @@
 
 #define ENV_OFFSET offsetof(MicroBlazeCPU, env)
 
+void mb_cpu_do_interrupt(CPUState *cs);
+
 #endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 81359db..0f4293d 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -131,6 +131,7 @@
     mcc->parent_reset = cc->reset;
     cc->reset = mb_cpu_reset;
 
+    cc->do_interrupt = mb_cpu_do_interrupt;
     dc->vmsd = &vmstate_mb_cpu;
 }
 
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 7548aa9..1813939 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -275,7 +275,6 @@
 void mb_tcg_init(void);
 MicroBlazeCPU *cpu_mb_init(const char *cpu_model);
 int cpu_mb_exec(CPUMBState *s);
-void do_interrupt(CPUMBState *env);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c
index 97aedc5..a0416d0 100644
--- a/target-microblaze/helper.c
+++ b/target-microblaze/helper.c
@@ -26,8 +26,11 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUMBState *env)
+void mb_cpu_do_interrupt(CPUState *cs)
 {
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUMBState *env = &cpu->env;
+
     env->exception_index = -1;
     env->res_addr = RES_ADDR_NONE;
     env->regs[14] = env->sregs[SR_PC];
@@ -109,8 +112,10 @@
     return r;
 }
 
-void do_interrupt(CPUMBState *env)
+void mb_cpu_do_interrupt(CPUState *cs)
 {
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUMBState *env = &cpu->env;
     uint32_t t;
 
     /* IMM flag cannot propagate across a branch and into the dslot.  */
diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h
index c6bcddf..32e3cad 100644
--- a/target-mips/cpu-qom.h
+++ b/target-mips/cpu-qom.h
@@ -74,4 +74,6 @@
 
 #define ENV_OFFSET offsetof(MIPSCPU, env)
 
+void mips_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 4d62031..5315f7b 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -78,6 +78,8 @@
 
     mcc->parent_reset = cc->reset;
     cc->reset = mips_cpu_reset;
+
+    cc->do_interrupt = mips_cpu_do_interrupt;
 }
 
 static const TypeInfo mips_cpu_type_info = {
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 22b0497..cedf03d 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -663,7 +663,6 @@
 int cpu_mips_handle_mmu_fault (CPUMIPSState *env, target_ulong address, int rw,
                                int mmu_idx);
 #define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
-void do_interrupt (CPUMIPSState *env);
 #if !defined(CONFIG_USER_ONLY)
 void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra);
 hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address,
diff --git a/target-mips/helper.c b/target-mips/helper.c
index e877b8d..3a54acf 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -396,10 +396,11 @@
 }
 #endif
 
-void do_interrupt (CPUMIPSState *env)
+void mips_cpu_do_interrupt(CPUState *cs)
 {
+    MIPSCPU *cpu = MIPS_CPU(cs);
+    CPUMIPSState *env = &cpu->env;
 #if !defined(CONFIG_USER_ONLY)
-    MIPSCPU *cpu = mips_env_get_cpu(env);
     target_ulong offset;
     int cause = -1;
     const char *name;
diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c
index 72d5e8d..ffe14f3 100644
--- a/target-openrisc/cpu.c
+++ b/target-openrisc/cpu.c
@@ -148,6 +148,7 @@
     cc->reset = openrisc_cpu_reset;
 
     cc->class_by_name = openrisc_cpu_class_by_name;
+    cc->do_interrupt = openrisc_cpu_do_interrupt;
 }
 
 static void cpu_register(const OpenRISCCPUInfo *info)
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 64370a3..b9c55ba 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -346,7 +346,7 @@
 
 void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf);
 int cpu_openrisc_exec(CPUOpenRISCState *s);
-void do_interrupt(CPUOpenRISCState *env);
+void openrisc_cpu_do_interrupt(CPUState *cpu);
 void openrisc_translate_init(void);
 int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
                                   target_ulong address,
diff --git a/target-openrisc/interrupt.c b/target-openrisc/interrupt.c
index 7f2c025..16ef4b3 100644
--- a/target-openrisc/interrupt.c
+++ b/target-openrisc/interrupt.c
@@ -25,8 +25,10 @@
 #include "hw/loader.h"
 #endif
 
-void do_interrupt(CPUOpenRISCState *env)
+void openrisc_cpu_do_interrupt(CPUState *cs)
 {
+    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+    CPUOpenRISCState *env = &cpu->env;
 #ifndef CONFIG_USER_ONLY
     if (env->flags & D_FLAG) { /* Delay Slot insn */
         env->flags &= ~D_FLAG;
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 2bf0ab6..09bfae3 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -95,4 +95,6 @@
 
 PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
 
+void ppc_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1b31b1d..6886666 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1133,7 +1133,6 @@
 int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
                               int mmu_idx);
 #define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
-void do_interrupt (CPUPPCState *env);
 void ppc_hw_interrupt (CPUPPCState *env);
 
 #if !defined(CONFIG_USER_ONLY)
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index d176734..4a0fc6d 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -38,8 +38,11 @@
 /*****************************************************************************/
 /* Exception processing */
 #if defined(CONFIG_USER_ONLY)
-void do_interrupt(CPUPPCState *env)
+void ppc_cpu_do_interrupt(CPUState *cs)
 {
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
     env->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 }
@@ -654,9 +657,10 @@
     }
 }
 
-void do_interrupt(CPUPPCState *env)
+void ppc_cpu_do_interrupt(CPUState *cs)
 {
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
 
     powerpc_excp(cpu, env->excp_model, env->exception_index);
 }
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 09ad4ba..15eebe9 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8427,6 +8427,7 @@
     cc->reset = ppc_cpu_reset;
 
     cc->class_by_name = ppc_cpu_class_by_name;
+    cc->do_interrupt = ppc_cpu_do_interrupt;
 }
 
 static const TypeInfo ppc_cpu_type_info = {
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index f6e5145..34d45c2 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -71,4 +71,6 @@
 
 #define ENV_OFFSET offsetof(S390CPU, env)
 
+void s390_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 738a0ad..23fe51f 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -169,6 +169,7 @@
     scc->parent_reset = cc->reset;
     cc->reset = s390_cpu_reset;
 
+    cc->do_interrupt = s390_cpu_do_interrupt;
     dc->vmsd = &vmstate_s390_cpu;
 }
 
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 642e661..e351005 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -315,7 +315,6 @@
 S390CPU *cpu_s390x_init(const char *cpu_model);
 void s390x_translate_init(void);
 int cpu_s390x_exec(CPUS390XState *s);
-void do_interrupt (CPUS390XState *env);
 
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 2cb8dc8..b425054 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -86,8 +86,11 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt(CPUS390XState *env)
+void s390_cpu_do_interrupt(CPUState *cs)
 {
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+
     env->exception_index = -1;
 }
 
@@ -737,10 +740,10 @@
     load_psw(env, mask, addr);
 }
 
-void do_interrupt(CPUS390XState *env)
+void s390_cpu_do_interrupt(CPUState *cs)
 {
-    S390CPU *cpu = s390_env_get_cpu(env);
-    CPUState *cs;
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
 
     qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n",
                   __func__, env->exception_index, env->psw.addr);
@@ -799,7 +802,6 @@
     env->exception_index = -1;
 
     if (!env->pending_int) {
-        cs = CPU(s390_env_get_cpu(env));
         cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
     }
 }
diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h
index 29628c8..f8c80d3 100644
--- a/target-sh4/cpu-qom.h
+++ b/target-sh4/cpu-qom.h
@@ -83,4 +83,6 @@
 
 #define ENV_OFFSET offsetof(SuperHCPU, env)
 
+void superh_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index 5251aa0..898aecd 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -273,6 +273,7 @@
     cc->reset = superh_cpu_reset;
 
     cc->class_by_name = superh_cpu_class_by_name;
+    cc->do_interrupt = superh_cpu_do_interrupt;
     dc->vmsd = &vmstate_sh_cpu;
 }
 
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index 4966355..fd7da92 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -196,7 +196,6 @@
 int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault
-void do_interrupt(CPUSH4State * env);
 
 void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 #if !defined(CONFIG_USER_ONLY)
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index fd4efee..0a9cb3a 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -31,9 +31,12 @@
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUSH4State *env)
+void superh_cpu_do_interrupt(CPUState *cs)
 {
-  env->exception_index = -1;
+    SuperHCPU *cpu = SUPERH_CPU(cs);
+    CPUSH4State *env = &cpu->env;
+
+    env->exception_index = -1;
 }
 
 int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
@@ -78,9 +81,10 @@
 #define MMU_DADDR_ERROR_READ     (-12)
 #define MMU_DADDR_ERROR_WRITE    (-13)
 
-void do_interrupt(CPUSH4State *env)
+void superh_cpu_do_interrupt(CPUState *cs)
 {
-    CPUState *cs = CPU(sh_env_get_cpu(env));
+    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;
 
diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h
index efeeca0..d4fe89e 100644
--- a/target-sparc/cpu-qom.h
+++ b/target-sparc/cpu-qom.h
@@ -75,4 +75,6 @@
 
 #define ENV_OFFSET offsetof(SPARCCPU, env)
 
+void sparc_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 50def61..ab1adfd 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -891,6 +891,8 @@
 
     scc->parent_reset = cc->reset;
     cc->reset = sparc_cpu_reset;
+
+    cc->do_interrupt = sparc_cpu_do_interrupt;
 }
 
 static const TypeInfo sparc_cpu_type_info = {
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 8a2f8df..6fa7778 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -553,7 +553,6 @@
 void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
 
 /* int_helper.c */
-void do_interrupt(CPUSPARCState *env);
 void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno);
 
 /* sun4m.c, sun4u.c */
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
index c35f522..7221460 100644
--- a/target-sparc/int32_helper.c
+++ b/target-sparc/int32_helper.c
@@ -58,8 +58,10 @@
 };
 #endif
 
-void do_interrupt(CPUSPARCState *env)
+void sparc_cpu_do_interrupt(CPUState *cs)
 {
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
     int cwp, intno = env->exception_index;
 
     /* Compute PSR before exposing state.  */
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
index df37aa1..f411884 100644
--- a/target-sparc/int64_helper.c
+++ b/target-sparc/int64_helper.c
@@ -59,8 +59,10 @@
 };
 #endif
 
-void do_interrupt(CPUSPARCState *env)
+void sparc_cpu_do_interrupt(CPUState *cs)
 {
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
     int intno = env->exception_index;
     trap_state *tsptr;
 
diff --git a/target-unicore32/cpu-qom.h b/target-unicore32/cpu-qom.h
index c6590bd..ba4dee4 100644
--- a/target-unicore32/cpu-qom.h
+++ b/target-unicore32/cpu-qom.h
@@ -60,4 +60,6 @@
 
 #define ENV_OFFSET offsetof(UniCore32CPU, env)
 
+void uc32_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index b7024c8..66a1a74 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -132,6 +132,7 @@
     dc->realize = uc32_cpu_realizefn;
 
     cc->class_by_name = uc32_cpu_class_by_name;
+    cc->do_interrupt = uc32_cpu_do_interrupt;
     dc->vmsd = &vmstate_uc32_cpu;
 }
 
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 58f1f20..5b2b9d1 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -176,7 +176,6 @@
 }
 
 void uc32_translate_init(void);
-void do_interrupt(CPUUniCore32State *);
 void switch_mode(CPUUniCore32State *, int);
 
 static inline bool cpu_has_work(CPUState *cpu)
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 7eeb9bc..61eb2c3 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -242,8 +242,11 @@
     }
 }
 
-void do_interrupt(CPUUniCore32State *env)
+void uc32_cpu_do_interrupt(CPUState *cs)
 {
+    UniCore32CPU *cpu = UNICORE32_CPU(cs);
+    CPUUniCore32State *env = &cpu->env;
+
     cpu_abort(env, "NO interrupt in user mode\n");
 }
 
diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c
index 1c4c7f5..eadaeb1 100644
--- a/target-unicore32/softmmu.c
+++ b/target-unicore32/softmmu.c
@@ -72,9 +72,10 @@
 }
 
 /* Handle a CPU exception.  */
-void do_interrupt(CPUUniCore32State *env)
+void uc32_cpu_do_interrupt(CPUState *cs)
 {
-    CPUState *cs = CPU(uc32_env_get_cpu(env));
+    UniCore32CPU *cpu = UNICORE32_CPU(cs);
+    CPUUniCore32State *env = &cpu->env;
     uint32_t addr;
     int new_mode;
 
diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
index c78136b..af0ce28 100644
--- a/target-xtensa/cpu-qom.h
+++ b/target-xtensa/cpu-qom.h
@@ -80,4 +80,6 @@
 
 #define ENV_OFFSET offsetof(XtensaCPU, env)
 
+void xtensa_cpu_do_interrupt(CPUState *cpu);
+
 #endif
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index 785e56d..6e93dd8 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -101,6 +101,7 @@
     xcc->parent_reset = cc->reset;
     cc->reset = xtensa_cpu_reset;
 
+    cc->do_interrupt = xtensa_cpu_do_interrupt;
     dc->vmsd = &vmstate_xtensa_cpu;
 }
 
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index dece224..6c9fc35 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -388,7 +388,6 @@
 void xtensa_breakpoint_handler(CPUXtensaState *env);
 int cpu_xtensa_exec(CPUXtensaState *s);
 void xtensa_register_core(XtensaConfigList *node);
-void do_interrupt(CPUXtensaState *s);
 void check_interrupts(CPUXtensaState *s);
 void xtensa_irq_init(CPUXtensaState *env);
 void *xtensa_get_extint(CPUXtensaState *env, unsigned extint);
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index a8a6493..6f613c66 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -178,8 +178,11 @@
     }
 }
 
-void do_interrupt(CPUXtensaState *env)
+void xtensa_cpu_do_interrupt(CPUState *cs)
 {
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+    CPUXtensaState *env = &cpu->env;
+
     if (env->exception_index == EXC_IRQ) {
         qemu_log_mask(CPU_LOG_INT,
                 "%s(EXC_IRQ) level = %d, cintlevel = %d, "