diff mbox series

[31/35] cpu: Move icount_decr to CPUNegativeOffsetState

Message ID 20190323190925.21324-32-richard.henderson@linaro.org
State New
Headers show
Series tcg: Move the softmmu tlb to CPUNegativeOffsetState | expand

Commit Message

Richard Henderson March 23, 2019, 7:09 p.m. UTC
Amusingly, we had already ignored the comment to keep this
value at the end of CPUState.  This restores the minimum
negative offset from TCG_AREG0 for code generation.

This is slightly complicated for qom/cpu.c and tcg-all.c,
in that they are compiled once.  This means we need an out
of line helper to access the icount_decr value.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---

RFC: I had problems with the build system moving qom/cpu.c
from common-obj-y to obj-y.  Then I tried just splitting out
a piece of it, and ran into odder build system issues.  Then
I hacked Makefile.target in a way that doesn't look right,
but works.

Question: Should I bother splitting qom/cpu.c at all?  Just
move the whole thing to obj-y (with non-broken build changes,
obviously, whatever that might be).


r~

---
 Makefile.target           |   1 +
 include/exec/cpu-defs.h   |   3 +-
 include/exec/gen-icount.h |  16 +-
 include/qom/cpu.h         |  28 +--
 accel/tcg/cpu-exec.c      |  23 ++-
 accel/tcg/tcg-all.c       |   6 +-
 accel/tcg/translate-all.c |   8 +-
 cpus.c                    |   9 +-
 qom/cpu-common.c          | 425 ++++++++++++++++++++++++++++++++++++++
 qom/cpu.c                 | 408 +-----------------------------------
 qom/Makefile.objs         |   2 +-
 11 files changed, 480 insertions(+), 449 deletions(-)
 create mode 100644 qom/cpu-common.c

-- 
2.17.1

Comments

Paolo Bonzini March 25, 2019, 5:23 p.m. UTC | #1
On 23/03/19 20:09, Richard Henderson wrote:
> Amusingly, we had already ignored the comment to keep this

> value at the end of CPUState.  This restores the minimum

> negative offset from TCG_AREG0 for code generation.

> 

> This is slightly complicated for qom/cpu.c and tcg-all.c,

> in that they are compiled once.  This means we need an out

> of line helper to access the icount_decr value.

> 

> Cc: Paolo Bonzini <pbonzini@redhat.com>

> Cc: Andreas Färber <afaerber@suse.de>

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> ---

> 

> RFC: I had problems with the build system moving qom/cpu.c

> from common-obj-y to obj-y.  Then I tried just splitting out

> a piece of it, and ran into odder build system issues.  Then

> I hacked Makefile.target in a way that doesn't look right,

> but works.

> 

> Question: Should I bother splitting qom/cpu.c at all?  Just

> move the whole thing to obj-y (with non-broken build changes,

> obviously, whatever that might be).


I think you should, because moving it to obj-y would be a major headache
if we ever were to resurrect the multiarch patches by Peter C.

That said, does cpu_neg really need env_neg and thus ArchCPU?  Perhaps
you could:

1) define CPUTLB in terms of MAX_MMU_MODES (12) instead of NB_MMU_MODES

2) assert that

   offsetof(ArchCPU, env) - offsetof(ArchCPU, neg) ==
      sizeof(CPUNegativeOffsetState)

3) use this in cpu_neg to go from cpu->env_ptr to the
CPUNegativeOffsetState.

This lets you implement cpu_neg in a target-independent manner.

Paolo
Richard Henderson March 25, 2019, 5:38 p.m. UTC | #2
On 3/25/19 10:23 AM, Paolo Bonzini wrote:
>> RFC: I had problems with the build system moving qom/cpu.c

>> from common-obj-y to obj-y.  Then I tried just splitting out

>> a piece of it, and ran into odder build system issues.  Then

>> I hacked Makefile.target in a way that doesn't look right,

>> but works.

>>

>> Question: Should I bother splitting qom/cpu.c at all?  Just

>> move the whole thing to obj-y (with non-broken build changes,

>> obviously, whatever that might be).

> 

> I think you should, because moving it to obj-y would be a major headache

> if we ever were to resurrect the multiarch patches by Peter C.

> 

> That said, does cpu_neg really need env_neg and thus ArchCPU?


At one point point during development I had a pointer in CPUState to the
icount_decr.  But I didn't like having to copy this initialization into
target/*/ as with the setting of env_ptr.


> 1) define CPUTLB in terms of MAX_MMU_MODES (12) instead of NB_MMU_MODES


Plausible, now that unused mmu modes consume < 100 bytes
instead of many kB.

> 

> 2) assert that

> 

>    offsetof(ArchCPU, env) - offsetof(ArchCPU, neg) ==

>       sizeof(CPUNegativeOffsetState)


This requires that alignof(neg) == alignof(env), lest there be extra padding in
between the two structures.  But perhaps that's just a matter of adjusting the
declaration like so:

    CPUNegativeOffsetState neg QEMU_ALIGNED(__alignof(CPUArchState));

In any case the _Static_assert would let us know.

> 

> 3) use this in cpu_neg to go from cpu->env_ptr to the

> CPUNegativeOffsetState.

> 

> This lets you implement cpu_neg in a target-independent manner.


Plausible.  Thanks for the feedback.


r~
Richard Henderson March 28, 2019, 8:21 p.m. UTC | #3
On 3/25/19 10:23 AM, Paolo Bonzini wrote:
> I think you should, because moving it to obj-y would be a major headache

> if we ever were to resurrect the multiarch patches by Peter C.

> 

> That said, does cpu_neg really need env_neg and thus ArchCPU?  Perhaps

> you could:

> 

> 1) define CPUTLB in terms of MAX_MMU_MODES (12) instead of NB_MMU_MODES

> 

> 2) assert that

> 

>    offsetof(ArchCPU, env) - offsetof(ArchCPU, neg) ==

>       sizeof(CPUNegativeOffsetState)


This doesn't work, since CPUTLB depends on target_ulong.

I think I'll go back to a pointer from CPUState to icount_decr, but clean up
how this and CPUState->env_ptr are initialized.


r~
diff mbox series

Patch

diff --git a/Makefile.target b/Makefile.target
index ae02495951..1fe3594768 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -117,6 +117,7 @@  obj-$(CONFIG_TCG) += fpu/softfloat.o
 obj-y += target/$(TARGET_BASE_ARCH)/
 obj-y += disas.o
 obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
+obj-y += qom/cpu.o
 
 #########################################################
 # Linux user emulator target
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index ad97991faf..73de706342 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -33,6 +33,7 @@ 
 #include "exec/hwaddr.h"
 #endif
 #include "exec/memattrs.h"
+#include "qom/cpu.h"
 
 #include "cpu-param.h"
 
@@ -232,7 +233,7 @@  typedef struct CPUTLB {
  * before CPUArchState, as a field named "neg".
  */
 typedef struct CPUNegativeOffsetState {
-    /* Empty */
+    icount_decr icount_decr;
 } CPUNegativeOffsetState;
 
 #endif
diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
index 9cfa6ccce5..f7669b6841 100644
--- a/include/exec/gen-icount.h
+++ b/include/exec/gen-icount.h
@@ -5,8 +5,6 @@ 
 
 /* Helpers for instruction counting code generation.  */
 
-#define ENV_OFFSET   offsetof(ArchCPU, env)
-
 static TCGOp *icount_start_insn;
 
 static inline void gen_tb_start(TranslationBlock *tb)
@@ -21,7 +19,8 @@  static inline void gen_tb_start(TranslationBlock *tb)
     }
 
     tcg_gen_ld_i32(count, cpu_env,
-                   -ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
+                   offsetof(ArchCPU, neg.icount_decr.u32) -
+                   offsetof(ArchCPU, env));
 
     if (tb_cflags(tb) & CF_USE_ICOUNT) {
         imm = tcg_temp_new_i32();
@@ -39,7 +38,8 @@  static inline void gen_tb_start(TranslationBlock *tb)
 
     if (tb_cflags(tb) & CF_USE_ICOUNT) {
         tcg_gen_st16_i32(count, cpu_env,
-                         -ENV_OFFSET + offsetof(CPUState, icount_decr.u16.low));
+                         offsetof(ArchCPU, neg.icount_decr.u16.low) -
+                         offsetof(ArchCPU, env));
     }
 
     tcg_temp_free_i32(count);
@@ -60,14 +60,18 @@  static inline void gen_tb_end(TranslationBlock *tb, int num_insns)
 static inline void gen_io_start(void)
 {
     TCGv_i32 tmp = tcg_const_i32(1);
-    tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io));
+    tcg_gen_st_i32(tmp, cpu_env,
+                   offsetof(ArchCPU, parent_obj.can_do_io) -
+                   offsetof(ArchCPU, env));
     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, -ENV_OFFSET + offsetof(CPUState, can_do_io));
+    tcg_gen_st_i32(tmp, cpu_env,
+                   offsetof(ArchCPU, parent_obj.can_do_io) -
+                   offsetof(ArchCPU, env));
     tcg_temp_free_i32(tmp);
 }
 
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 1d6099e5d4..ee0159c97d 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -241,6 +241,18 @@  typedef struct icount_decr_u16 {
 } icount_decr_u16;
 #endif
 
+/*
+ * Low 16 bits: number of cycles left, used only in icount mode.
+ * High 16 bits: Set to -1 to force TCG to stop executing linked TBs
+ * for this CPU and return to its top level loop (even in non-icount mode).
+ * This allows a single read-compare-cbranch-write sequence to test
+ * for both decrementer underflow and exceptions.
+ */
+typedef union icount_decr {
+    uint32_t u32;
+    icount_decr_u16 u16;
+} icount_decr;
+
 typedef struct CPUBreakpoint {
     vaddr pc;
     int flags; /* BP_* */
@@ -311,11 +323,6 @@  struct qemu_work_item;
  * @crash_occurred: Indicates the OS reported a crash (panic) for this CPU
  * @singlestep_enabled: Flags for single-stepping.
  * @icount_extra: Instructions until next timer event.
- * @icount_decr: Low 16 bits: number of cycles left, only used in icount mode.
- * High 16 bits: Set to -1 to force TCG to stop executing linked TBs for this
- * CPU and return to its top level loop (even in non-icount mode).
- * 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. Deterministic execution
  * requires that IO only be performed on the last instruction of a TB
  * so that interrupts take effect immediately.
@@ -437,15 +444,6 @@  struct CPUState {
 
     bool ignore_memory_transaction_failures;
 
-    /* Note that this is accessed at the start of every TB via a negative
-       offset from AREG0.  Leave this field at the end so as to make the
-       (absolute value) offset as small as possible.  This reduces code
-       size, especially for hosts without large memory offsets.  */
-    union {
-        uint32_t u32;
-        icount_decr_u16 u16;
-    } icount_decr;
-
     struct hax_vcpu_state *hax_vcpu;
 
     int hvf_fd;
@@ -1110,6 +1108,8 @@  void cpu_exec_unrealizefn(CPUState *cpu);
  */
 bool target_words_bigendian(void);
 
+void cpu_common_reset(CPUState *cpu);
+
 #ifdef NEED_CPU_H
 
 #ifdef CONFIG_SOFTMMU
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 45ef41ebb2..032a62672e 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -54,7 +54,7 @@  typedef struct SyncClocks {
 #define MAX_DELAY_PRINT_RATE 2000000000LL
 #define MAX_NB_PRINTS 100
 
-static void align_clocks(SyncClocks *sc, const CPUState *cpu)
+static void align_clocks(SyncClocks *sc, CPUState *cpu)
 {
     int64_t cpu_icount;
 
@@ -62,7 +62,7 @@  static void align_clocks(SyncClocks *sc, const CPUState *cpu)
         return;
     }
 
-    cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low;
+    cpu_icount = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low;
     sc->diff_clk += cpu_icount_to_ns(sc->last_cpu_icount - cpu_icount);
     sc->last_cpu_icount = cpu_icount;
 
@@ -105,15 +105,15 @@  static void print_delay(const SyncClocks *sc)
     }
 }
 
-static void init_delay_params(SyncClocks *sc,
-                              const CPUState *cpu)
+static void init_delay_params(SyncClocks *sc, CPUState *cpu)
 {
     if (!icount_align_option) {
         return;
     }
     sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
     sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sc->realtime_clock;
-    sc->last_cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low;
+    sc->last_cpu_icount
+        = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low;
     if (sc->diff_clk < max_delay) {
         max_delay = sc->diff_clk;
     }
@@ -467,7 +467,7 @@  static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
     if (cpu->exception_index < 0) {
 #ifndef CONFIG_USER_ONLY
         if (replay_has_exception()
-               && cpu->icount_decr.u16.low + cpu->icount_extra == 0) {
+            && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) {
             /* try to cause an exception pending in the log */
             cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0, curr_cflags()), true);
         }
@@ -525,7 +525,7 @@  static inline bool cpu_handle_interrupt(CPUState *cpu,
      * Ensure zeroing happens before reading cpu->exit_request or
      * cpu->interrupt_request (see also smp_wmb in cpu_exit())
      */
-    atomic_mb_set(&cpu->icount_decr.u16.high, 0);
+    atomic_mb_set(&cpu_neg(cpu)->icount_decr.u16.high, 0);
 
     if (unlikely(atomic_read(&cpu->interrupt_request))) {
         int interrupt_request;
@@ -596,8 +596,9 @@  static inline bool cpu_handle_interrupt(CPUState *cpu,
     }
 
     /* Finally, check if we need to exit to the main loop.  */
-    if (unlikely(atomic_read(&cpu->exit_request)
-        || (use_icount && cpu->icount_decr.u16.low + cpu->icount_extra == 0))) {
+    if (unlikely(atomic_read(&cpu->exit_request))
+        || (use_icount
+            && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) {
         atomic_set(&cpu->exit_request, 0);
         if (cpu->exception_index == -1) {
             cpu->exception_index = EXCP_INTERRUPT;
@@ -624,7 +625,7 @@  static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
     }
 
     *last_tb = NULL;
-    insns_left = atomic_read(&cpu->icount_decr.u32);
+    insns_left = atomic_read(&cpu_neg(cpu)->icount_decr.u32);
     if (insns_left < 0) {
         /* Something asked us to stop executing chained TBs; just
          * continue round the main loop. Whatever requested the exit
@@ -643,7 +644,7 @@  static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
     cpu_update_icount(cpu);
     /* Refill decrementer and continue execution.  */
     insns_left = MIN(0xffff, cpu->icount_budget);
-    cpu->icount_decr.u16.low = insns_left;
+    cpu_neg(cpu)->icount_decr.u16.low = insns_left;
     cpu->icount_extra = cpu->icount_budget - insns_left;
     if (!cpu->icount_extra) {
         /* Execute any remaining instructions, then let the main loop
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
index 3d25bdcc17..9b215dcc5a 100644
--- a/accel/tcg/tcg-all.c
+++ b/accel/tcg/tcg-all.c
@@ -28,13 +28,12 @@ 
 #include "sysemu/sysemu.h"
 #include "qom/object.h"
 #include "qemu-common.h"
-#include "qom/cpu.h"
+#include "cpu.h"
 #include "sysemu/cpus.h"
 #include "qemu/main-loop.h"
 
 unsigned long tcg_tb_size;
 
-#ifndef CONFIG_USER_ONLY
 /* mask must never be zero, except for A20 change call */
 static void tcg_handle_interrupt(CPUState *cpu, int mask)
 {
@@ -51,7 +50,7 @@  static void tcg_handle_interrupt(CPUState *cpu, int mask)
     if (!qemu_cpu_is_self(cpu)) {
         qemu_cpu_kick(cpu);
     } else {
-        atomic_set(&cpu->icount_decr.u16.high, -1);
+        atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1);
         if (use_icount &&
             !cpu->can_do_io
             && (mask & ~old_mask) != 0) {
@@ -59,7 +58,6 @@  static void tcg_handle_interrupt(CPUState *cpu, int mask)
         }
     }
 }
-#endif
 
 static int tcg_init(MachineState *ms)
 {
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 2cc5d3c59f..ed19a41d55 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -363,7 +363,7 @@  static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
         assert(use_icount);
         /* Reset the cycle counter to the start of the block
            and shift if to the number of actually executed instructions */
-        cpu->icount_decr.u16.low += num_insns - i;
+        cpu_neg(cpu)->icount_decr.u16.low += num_insns - i;
     }
     restore_state_to_opc(env, tb, data);
 
@@ -2162,7 +2162,7 @@  void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
     if ((env->hflags & MIPS_HFLAG_BMASK) != 0
         && env->active_tc.PC != tb->pc) {
         env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
-        cpu->icount_decr.u16.low++;
+        cpu_neg(cpu)->icount_decr.u16.low++;
         env->hflags &= ~MIPS_HFLAG_BMASK;
         n = 2;
     }
@@ -2170,7 +2170,7 @@  void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
     if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
         && env->pc != tb->pc) {
         env->pc -= 2;
-        cpu->icount_decr.u16.low++;
+        cpu_neg(cpu)->icount_decr.u16.low++;
         env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
         n = 2;
     }
@@ -2344,7 +2344,7 @@  void cpu_interrupt(CPUState *cpu, int mask)
 {
     g_assert(qemu_mutex_iothread_locked());
     cpu->interrupt_request |= mask;
-    atomic_set(&cpu->icount_decr.u16.high, -1);
+    atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1);
 }
 
 /*
diff --git a/cpus.c b/cpus.c
index e83f72b48b..b123ef541e 100644
--- a/cpus.c
+++ b/cpus.c
@@ -237,7 +237,8 @@  void qemu_tcg_configure(QemuOpts *opts, Error **errp)
  */
 static int64_t cpu_get_icount_executed(CPUState *cpu)
 {
-    return cpu->icount_budget - (cpu->icount_decr.u16.low + cpu->icount_extra);
+    return (cpu->icount_budget -
+            (cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra));
 }
 
 /*
@@ -1385,12 +1386,12 @@  static void prepare_icount_for_run(CPUState *cpu)
          * each vCPU execution. However u16.high can be raised
          * asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt
          */
-        g_assert(cpu->icount_decr.u16.low == 0);
+        g_assert(cpu_neg(cpu)->icount_decr.u16.low == 0);
         g_assert(cpu->icount_extra == 0);
 
         cpu->icount_budget = tcg_get_icount_limit();
         insns_left = MIN(0xffff, cpu->icount_budget);
-        cpu->icount_decr.u16.low = insns_left;
+        cpu_neg(cpu)->icount_decr.u16.low = insns_left;
         cpu->icount_extra = cpu->icount_budget - insns_left;
 
         replay_mutex_lock();
@@ -1404,7 +1405,7 @@  static void process_icount_data(CPUState *cpu)
         cpu_update_icount(cpu);
 
         /* Reset the counters */
-        cpu->icount_decr.u16.low = 0;
+        cpu_neg(cpu)->icount_decr.u16.low = 0;
         cpu->icount_extra = 0;
         cpu->icount_budget = 0;
 
diff --git a/qom/cpu-common.c b/qom/cpu-common.c
new file mode 100644
index 0000000000..81d3821899
--- /dev/null
+++ b/qom/cpu-common.c
@@ -0,0 +1,425 @@ 
+/*
+ * QEMU CPU model
+ *
+ * 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "qom/cpu.h"
+#include "sysemu/hw_accel.h"
+#include "qemu/notify.h"
+#include "qemu/log.h"
+#include "exec/log.h"
+#include "exec/cpu-common.h"
+#include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "trace-root.h"
+
+CPUInterruptHandler cpu_interrupt_handler;
+
+CPUState *cpu_by_arch_id(int64_t id)
+{
+    CPUState *cpu;
+
+    CPU_FOREACH(cpu) {
+        CPUClass *cc = CPU_GET_CLASS(cpu);
+
+        if (cc->get_arch_id(cpu) == id) {
+            return cpu;
+        }
+    }
+    return NULL;
+}
+
+bool cpu_exists(int64_t id)
+{
+    return !!cpu_by_arch_id(id);
+}
+
+CPUState *cpu_create(const char *typename)
+{
+    Error *err = NULL;
+    CPUState *cpu = CPU(object_new(typename));
+    object_property_set_bool(OBJECT(cpu), true, "realized", &err);
+    if (err != NULL) {
+        error_report_err(err);
+        object_unref(OBJECT(cpu));
+        exit(EXIT_FAILURE);
+    }
+    return cpu;
+}
+
+bool cpu_paging_enabled(const CPUState *cpu)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    return cc->get_paging_enabled(cpu);
+}
+
+static bool cpu_common_get_paging_enabled(const CPUState *cpu)
+{
+    return false;
+}
+
+void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
+                            Error **errp)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    cc->get_memory_mapping(cpu, list, errp);
+}
+
+static void cpu_common_get_memory_mapping(CPUState *cpu,
+                                          MemoryMappingList *list,
+                                          Error **errp)
+{
+    error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
+}
+
+/* Resetting the IRQ comes from across the code base so we take the
+ * BQL here if we need to.  cpu_interrupt assumes it is held.*/
+void cpu_reset_interrupt(CPUState *cpu, int mask)
+{
+    bool need_lock = !qemu_mutex_iothread_locked();
+
+    if (need_lock) {
+        qemu_mutex_lock_iothread();
+    }
+    cpu->interrupt_request &= ~mask;
+    if (need_lock) {
+        qemu_mutex_unlock_iothread();
+    }
+}
+
+int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
+                             void *opaque)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    return (*cc->write_elf32_qemunote)(f, cpu, opaque);
+}
+
+static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f,
+                                           CPUState *cpu, void *opaque)
+{
+    return 0;
+}
+
+int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
+                         int cpuid, void *opaque)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    return (*cc->write_elf32_note)(f, cpu, cpuid, opaque);
+}
+
+static int cpu_common_write_elf32_note(WriteCoreDumpFunction f,
+                                       CPUState *cpu, int cpuid,
+                                       void *opaque)
+{
+    return -1;
+}
+
+int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
+                             void *opaque)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    return (*cc->write_elf64_qemunote)(f, cpu, opaque);
+}
+
+static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f,
+                                           CPUState *cpu, void *opaque)
+{
+    return 0;
+}
+
+int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
+                         int cpuid, void *opaque)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    return (*cc->write_elf64_note)(f, cpu, cpuid, opaque);
+}
+
+static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
+                                       CPUState *cpu, int cpuid,
+                                       void *opaque)
+{
+    return -1;
+}
+
+
+static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
+{
+    return 0;
+}
+
+static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
+{
+    return 0;
+}
+
+static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp)
+{
+    /* If no extra check is required, QEMU watchpoint match can be considered
+     * as an architectural match.
+     */
+    return true;
+}
+
+static bool cpu_common_virtio_is_big_endian(CPUState *cpu)
+{
+    return target_words_bigendian();
+}
+
+static void cpu_common_noop(CPUState *cpu)
+{
+}
+
+static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req)
+{
+    return false;
+}
+
+GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    GuestPanicInformation *res = NULL;
+
+    if (cc->get_crash_info) {
+        res = cc->get_crash_info(cpu);
+    }
+    return res;
+}
+
+void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    if (cc->dump_state) {
+        cpu_synchronize_state(cpu);
+        cc->dump_state(cpu, f, cpu_fprintf, flags);
+    }
+}
+
+void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
+                         int flags)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    if (cc->dump_statistics) {
+        cc->dump_statistics(cpu, f, cpu_fprintf, flags);
+    }
+}
+
+void cpu_reset(CPUState *cpu)
+{
+    CPUClass *klass = CPU_GET_CLASS(cpu);
+
+    if (klass->reset != NULL) {
+        (*klass->reset)(cpu);
+    }
+
+    trace_guest_cpu_reset(cpu);
+}
+
+static bool cpu_common_has_work(CPUState *cs)
+{
+    return false;
+}
+
+ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
+{
+    CPUClass *cc = CPU_CLASS(object_class_by_name(typename));
+
+    assert(cpu_model && cc->class_by_name);
+    return cc->class_by_name(cpu_model);
+}
+
+static void cpu_common_parse_features(const char *typename, char *features,
+                                      Error **errp)
+{
+    char *val;
+    static bool cpu_globals_initialized;
+    /* Single "key=value" string being parsed */
+    char *featurestr = features ? strtok(features, ",") : NULL;
+
+    /* should be called only once, catch invalid users */
+    assert(!cpu_globals_initialized);
+    cpu_globals_initialized = true;
+
+    while (featurestr) {
+        val = strchr(featurestr, '=');
+        if (val) {
+            GlobalProperty *prop = g_new0(typeof(*prop), 1);
+            *val = 0;
+            val++;
+            prop->driver = typename;
+            prop->property = g_strdup(featurestr);
+            prop->value = g_strdup(val);
+            qdev_prop_register_global(prop);
+        } 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);
+    Object *machine = qdev_get_machine();
+
+    /* qdev_get_machine() can return something that's not TYPE_MACHINE
+     * if this is one of the user-only emulators; in that case there's
+     * no need to check the ignore_memory_transaction_failures board flag.
+     */
+    if (object_dynamic_cast(machine, TYPE_MACHINE)) {
+        ObjectClass *oc = object_get_class(machine);
+        MachineClass *mc = MACHINE_CLASS(oc);
+
+        if (mc) {
+            cpu->ignore_memory_transaction_failures =
+                mc->ignore_memory_transaction_failures;
+        }
+    }
+
+    if (dev->hotplugged) {
+        cpu_synchronize_post_init(cpu);
+        cpu_resume(cpu);
+    }
+
+    /* NOTE: latest generic point where the cpu is fully realized */
+    trace_init_vcpu(cpu);
+}
+
+static void cpu_common_unrealizefn(DeviceState *dev, Error **errp)
+{
+    CPUState *cpu = CPU(dev);
+    /* NOTE: latest generic point before the cpu is fully unrealized */
+    trace_fini_vcpu(cpu);
+    cpu_exec_unrealizefn(cpu);
+}
+
+static void cpu_common_initfn(Object *obj)
+{
+    CPUState *cpu = CPU(obj);
+    CPUClass *cc = CPU_GET_CLASS(obj);
+
+    cpu->cpu_index = UNASSIGNED_CPU_INDEX;
+    cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
+    cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
+    /* *-user doesn't have configurable SMP topology */
+    /* the default value is changed by qemu_init_vcpu() for softmmu */
+    cpu->nr_cores = 1;
+    cpu->nr_threads = 1;
+
+    qemu_mutex_init(&cpu->work_mutex);
+    QTAILQ_INIT(&cpu->breakpoints);
+    QTAILQ_INIT(&cpu->watchpoints);
+
+    cpu_exec_initfn(cpu);
+}
+
+static void cpu_common_finalize(Object *obj)
+{
+    CPUState *cpu = CPU(obj);
+
+    qemu_mutex_destroy(&cpu->work_mutex);
+}
+
+static int64_t cpu_common_get_arch_id(CPUState *cpu)
+{
+    return cpu->cpu_index;
+}
+
+static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len)
+{
+    return addr;
+}
+
+static void generic_handle_interrupt(CPUState *cpu, int mask)
+{
+    cpu->interrupt_request |= mask;
+
+    if (!qemu_cpu_is_self(cpu)) {
+        qemu_cpu_kick(cpu);
+    }
+}
+
+CPUInterruptHandler cpu_interrupt_handler = generic_handle_interrupt;
+
+static void cpu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    CPUClass *k = CPU_CLASS(klass);
+
+    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;
+    k->write_elf32_note = cpu_common_write_elf32_note;
+    k->write_elf64_qemunote = cpu_common_write_elf64_qemunote;
+    k->write_elf64_note = cpu_common_write_elf64_note;
+    k->gdb_read_register = cpu_common_gdb_read_register;
+    k->gdb_write_register = cpu_common_gdb_write_register;
+    k->virtio_is_big_endian = cpu_common_virtio_is_big_endian;
+    k->debug_excp_handler = cpu_common_noop;
+    k->debug_check_watchpoint = cpu_common_debug_check_watchpoint;
+    k->cpu_exec_enter = cpu_common_noop;
+    k->cpu_exec_exit = cpu_common_noop;
+    k->cpu_exec_interrupt = cpu_common_exec_interrupt;
+    k->adjust_watchpoint_address = cpu_adjust_watchpoint_address;
+    set_bit(DEVICE_CATEGORY_CPU, dc->categories);
+    dc->realize = cpu_common_realizefn;
+    dc->unrealize = cpu_common_unrealizefn;
+    dc->props = cpu_common_props;
+    /*
+     * Reason: CPUs still need special care by board code: wiring up
+     * IRQs, adding reset handlers, halting non-first CPUs, ...
+     */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo cpu_type_info = {
+    .name = TYPE_CPU,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(CPUState),
+    .instance_init = cpu_common_initfn,
+    .instance_finalize = cpu_common_finalize,
+    .abstract = true,
+    .class_size = sizeof(CPUClass),
+    .class_init = cpu_class_init,
+};
+
+static void cpu_register_types(void)
+{
+    type_register_static(&cpu_type_info);
+}
+
+type_init(cpu_register_types)
diff --git a/qom/cpu.c b/qom/cpu.c
index a8d2958956..830291a976 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -21,237 +21,18 @@ 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "qemu-common.h"
-#include "qom/cpu.h"
-#include "sysemu/hw_accel.h"
-#include "qemu/notify.h"
-#include "qemu/log.h"
+#include "cpu.h"
 #include "exec/log.h"
-#include "exec/cpu-common.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/qdev-properties.h"
-#include "trace-root.h"
-
-CPUInterruptHandler cpu_interrupt_handler;
-
-CPUState *cpu_by_arch_id(int64_t id)
-{
-    CPUState *cpu;
-
-    CPU_FOREACH(cpu) {
-        CPUClass *cc = CPU_GET_CLASS(cpu);
-
-        if (cc->get_arch_id(cpu) == id) {
-            return cpu;
-        }
-    }
-    return NULL;
-}
-
-bool cpu_exists(int64_t id)
-{
-    return !!cpu_by_arch_id(id);
-}
-
-CPUState *cpu_create(const char *typename)
-{
-    Error *err = NULL;
-    CPUState *cpu = CPU(object_new(typename));
-    object_property_set_bool(OBJECT(cpu), true, "realized", &err);
-    if (err != NULL) {
-        error_report_err(err);
-        object_unref(OBJECT(cpu));
-        exit(EXIT_FAILURE);
-    }
-    return cpu;
-}
-
-bool cpu_paging_enabled(const CPUState *cpu)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    return cc->get_paging_enabled(cpu);
-}
-
-static bool cpu_common_get_paging_enabled(const CPUState *cpu)
-{
-    return false;
-}
-
-void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
-                            Error **errp)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    cc->get_memory_mapping(cpu, list, errp);
-}
-
-static void cpu_common_get_memory_mapping(CPUState *cpu,
-                                          MemoryMappingList *list,
-                                          Error **errp)
-{
-    error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
-}
-
-/* Resetting the IRQ comes from across the code base so we take the
- * BQL here if we need to.  cpu_interrupt assumes it is held.*/
-void cpu_reset_interrupt(CPUState *cpu, int mask)
-{
-    bool need_lock = !qemu_mutex_iothread_locked();
-
-    if (need_lock) {
-        qemu_mutex_lock_iothread();
-    }
-    cpu->interrupt_request &= ~mask;
-    if (need_lock) {
-        qemu_mutex_unlock_iothread();
-    }
-}
 
 void cpu_exit(CPUState *cpu)
 {
     atomic_set(&cpu->exit_request, 1);
     /* Ensure cpu_exec will see the exit request after TCG has exited.  */
     smp_wmb();
-    atomic_set(&cpu->icount_decr.u16.high, -1);
+    atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1);
 }
 
-int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
-                             void *opaque)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    return (*cc->write_elf32_qemunote)(f, cpu, opaque);
-}
-
-static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f,
-                                           CPUState *cpu, void *opaque)
-{
-    return 0;
-}
-
-int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
-                         int cpuid, void *opaque)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    return (*cc->write_elf32_note)(f, cpu, cpuid, opaque);
-}
-
-static int cpu_common_write_elf32_note(WriteCoreDumpFunction f,
-                                       CPUState *cpu, int cpuid,
-                                       void *opaque)
-{
-    return -1;
-}
-
-int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
-                             void *opaque)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    return (*cc->write_elf64_qemunote)(f, cpu, opaque);
-}
-
-static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f,
-                                           CPUState *cpu, void *opaque)
-{
-    return 0;
-}
-
-int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
-                         int cpuid, void *opaque)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    return (*cc->write_elf64_note)(f, cpu, cpuid, opaque);
-}
-
-static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
-                                       CPUState *cpu, int cpuid,
-                                       void *opaque)
-{
-    return -1;
-}
-
-
-static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
-{
-    return 0;
-}
-
-static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
-{
-    return 0;
-}
-
-static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp)
-{
-    /* If no extra check is required, QEMU watchpoint match can be considered
-     * as an architectural match.
-     */
-    return true;
-}
-
-static bool cpu_common_virtio_is_big_endian(CPUState *cpu)
-{
-    return target_words_bigendian();
-}
-
-static void cpu_common_noop(CPUState *cpu)
-{
-}
-
-static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req)
-{
-    return false;
-}
-
-GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-    GuestPanicInformation *res = NULL;
-
-    if (cc->get_crash_info) {
-        res = cc->get_crash_info(cpu);
-    }
-    return res;
-}
-
-void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
-                    int flags)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    if (cc->dump_state) {
-        cpu_synchronize_state(cpu);
-        cc->dump_state(cpu, f, cpu_fprintf, flags);
-    }
-}
-
-void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
-                         int flags)
-{
-    CPUClass *cc = CPU_GET_CLASS(cpu);
-
-    if (cc->dump_statistics) {
-        cc->dump_statistics(cpu, f, cpu_fprintf, flags);
-    }
-}
-
-void cpu_reset(CPUState *cpu)
-{
-    CPUClass *klass = CPU_GET_CLASS(cpu);
-
-    if (klass->reset != NULL) {
-        (*klass->reset)(cpu);
-    }
-
-    trace_guest_cpu_reset(cpu);
-}
-
-static void cpu_common_reset(CPUState *cpu)
+void cpu_common_reset(CPUState *cpu)
 {
     CPUClass *cc = CPU_GET_CLASS(cpu);
 
@@ -265,7 +46,7 @@  static void cpu_common_reset(CPUState *cpu)
     cpu->mem_io_pc = 0;
     cpu->mem_io_vaddr = 0;
     cpu->icount_extra = 0;
-    atomic_set(&cpu->icount_decr.u32, 0);
+    atomic_set(&cpu_neg(cpu)->icount_decr.u32, 0);
     cpu->can_do_io = 1;
     cpu->exception_index = -1;
     cpu->crash_occurred = false;
@@ -277,184 +58,3 @@  static void cpu_common_reset(CPUState *cpu)
         tcg_flush_softmmu_tlb(cpu);
     }
 }
-
-static bool cpu_common_has_work(CPUState *cs)
-{
-    return false;
-}
-
-ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
-{
-    CPUClass *cc = CPU_CLASS(object_class_by_name(typename));
-
-    assert(cpu_model && cc->class_by_name);
-    return cc->class_by_name(cpu_model);
-}
-
-static void cpu_common_parse_features(const char *typename, char *features,
-                                      Error **errp)
-{
-    char *val;
-    static bool cpu_globals_initialized;
-    /* Single "key=value" string being parsed */
-    char *featurestr = features ? strtok(features, ",") : NULL;
-
-    /* should be called only once, catch invalid users */
-    assert(!cpu_globals_initialized);
-    cpu_globals_initialized = true;
-
-    while (featurestr) {
-        val = strchr(featurestr, '=');
-        if (val) {
-            GlobalProperty *prop = g_new0(typeof(*prop), 1);
-            *val = 0;
-            val++;
-            prop->driver = typename;
-            prop->property = g_strdup(featurestr);
-            prop->value = g_strdup(val);
-            qdev_prop_register_global(prop);
-        } 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);
-    Object *machine = qdev_get_machine();
-
-    /* qdev_get_machine() can return something that's not TYPE_MACHINE
-     * if this is one of the user-only emulators; in that case there's
-     * no need to check the ignore_memory_transaction_failures board flag.
-     */
-    if (object_dynamic_cast(machine, TYPE_MACHINE)) {
-        ObjectClass *oc = object_get_class(machine);
-        MachineClass *mc = MACHINE_CLASS(oc);
-
-        if (mc) {
-            cpu->ignore_memory_transaction_failures =
-                mc->ignore_memory_transaction_failures;
-        }
-    }
-
-    if (dev->hotplugged) {
-        cpu_synchronize_post_init(cpu);
-        cpu_resume(cpu);
-    }
-
-    /* NOTE: latest generic point where the cpu is fully realized */
-    trace_init_vcpu(cpu);
-}
-
-static void cpu_common_unrealizefn(DeviceState *dev, Error **errp)
-{
-    CPUState *cpu = CPU(dev);
-    /* NOTE: latest generic point before the cpu is fully unrealized */
-    trace_fini_vcpu(cpu);
-    cpu_exec_unrealizefn(cpu);
-}
-
-static void cpu_common_initfn(Object *obj)
-{
-    CPUState *cpu = CPU(obj);
-    CPUClass *cc = CPU_GET_CLASS(obj);
-
-    cpu->cpu_index = UNASSIGNED_CPU_INDEX;
-    cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
-    cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
-    /* *-user doesn't have configurable SMP topology */
-    /* the default value is changed by qemu_init_vcpu() for softmmu */
-    cpu->nr_cores = 1;
-    cpu->nr_threads = 1;
-
-    qemu_mutex_init(&cpu->work_mutex);
-    QTAILQ_INIT(&cpu->breakpoints);
-    QTAILQ_INIT(&cpu->watchpoints);
-
-    cpu_exec_initfn(cpu);
-}
-
-static void cpu_common_finalize(Object *obj)
-{
-    CPUState *cpu = CPU(obj);
-
-    qemu_mutex_destroy(&cpu->work_mutex);
-}
-
-static int64_t cpu_common_get_arch_id(CPUState *cpu)
-{
-    return cpu->cpu_index;
-}
-
-static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len)
-{
-    return addr;
-}
-
-static void generic_handle_interrupt(CPUState *cpu, int mask)
-{
-    cpu->interrupt_request |= mask;
-
-    if (!qemu_cpu_is_self(cpu)) {
-        qemu_cpu_kick(cpu);
-    }
-}
-
-CPUInterruptHandler cpu_interrupt_handler = generic_handle_interrupt;
-
-static void cpu_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    CPUClass *k = CPU_CLASS(klass);
-
-    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;
-    k->write_elf32_note = cpu_common_write_elf32_note;
-    k->write_elf64_qemunote = cpu_common_write_elf64_qemunote;
-    k->write_elf64_note = cpu_common_write_elf64_note;
-    k->gdb_read_register = cpu_common_gdb_read_register;
-    k->gdb_write_register = cpu_common_gdb_write_register;
-    k->virtio_is_big_endian = cpu_common_virtio_is_big_endian;
-    k->debug_excp_handler = cpu_common_noop;
-    k->debug_check_watchpoint = cpu_common_debug_check_watchpoint;
-    k->cpu_exec_enter = cpu_common_noop;
-    k->cpu_exec_exit = cpu_common_noop;
-    k->cpu_exec_interrupt = cpu_common_exec_interrupt;
-    k->adjust_watchpoint_address = cpu_adjust_watchpoint_address;
-    set_bit(DEVICE_CATEGORY_CPU, dc->categories);
-    dc->realize = cpu_common_realizefn;
-    dc->unrealize = cpu_common_unrealizefn;
-    dc->props = cpu_common_props;
-    /*
-     * Reason: CPUs still need special care by board code: wiring up
-     * IRQs, adding reset handlers, halting non-first CPUs, ...
-     */
-    dc->user_creatable = false;
-}
-
-static const TypeInfo cpu_type_info = {
-    .name = TYPE_CPU,
-    .parent = TYPE_DEVICE,
-    .instance_size = sizeof(CPUState),
-    .instance_init = cpu_common_initfn,
-    .instance_finalize = cpu_common_finalize,
-    .abstract = true,
-    .class_size = sizeof(CPUClass),
-    .class_init = cpu_class_init,
-};
-
-static void cpu_register_types(void)
-{
-    type_register_static(&cpu_type_info);
-}
-
-type_init(cpu_register_types)
diff --git a/qom/Makefile.objs b/qom/Makefile.objs
index 516349eec3..14506e0c2f 100644
--- a/qom/Makefile.objs
+++ b/qom/Makefile.objs
@@ -1,4 +1,4 @@ 
 qom-obj-y = object.o container.o qom-qobject.o
 qom-obj-y += object_interfaces.o
 
-common-obj-y = cpu.o
+common-obj-y = cpu-common.o