Patchwork [12/19] Add a query-cputypes command to QMP

login
register
mail settings
Submitter Daniel P. Berrange
Date June 7, 2010, 2:42 p.m.
Message ID <1275921752-29420-13-git-send-email-berrange@redhat.com>
Download mbox | patch
Permalink /patch/54872/
State New
Headers show

Comments

Daniel P. Berrange - June 7, 2010, 2:42 p.m.
This adds a new QMP command called 'query-cputypes' to allow
for discovery of CPU types known to the QEMU binary. This is
intended to relpace the need to parse '-cpu ?', '-cpu ?model'
and '-cpu ?dump'

Most targets have a simple structure listing just the CPU
model names (and optionally a 'description'), with room for
future expansion of extra attributes against each model

  {
      "cputypes": {
          "models": [
              {
                  "name": "arm926"
              },
              {
                  "name": "arm946"
              },
              {
                  "name": "arm1026"
              },
              ....
          ]
      }
  }

The sparc and x86 targets have extra architecture specific
metatadata. These are in keys 'x86info' and 'sparcinfo'
against each CPU model dict. These keys are repeated at the
top level to give data about all allowed feature names

A trimmed example:

{
    "cputypes": {
        "models": [
            {
                "name": "n270",
                "description": "Intel(R) Atom(TM) CPU N270   @ 1.60GHz",
                "x86info": {
                    "xlevel": 2147483658,
                    "family": 6,
                    "vendor": "",
                    "level": 5,
                    "model": 28,
                    "stepping": 2,
                    "features": {
                        "ext_edx": [
                            "lahf_lm"
                        ],
                        "edx": [
                            "pbe",
                            "tm",
                            "ht",
                            "ss",
                            "sse2",
                            ...
                        ]
                    }
                }
            }
        ],
        "x86info": {
            "features": {
                "ext_edx": [
                    21,
                    20,
                    "nodeid_msr",
                    "cvt16",
                    17,
                    "fma4",
                    15,
                    14,
                    "wdt",
                    ....
                ]
            }
        }
    }
}

No mapping to the legacy readline monitor is provided

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 cpus.c                       |   78 +++++++++++++++++++++++++++++++++++++++++
 cpus.h                       |    1 +
 monitor.c                    |    9 +++++
 target-arm/cpu.h             |    7 ++++
 target-arm/helper.c          |   21 +++++++++++
 target-cris/cpu.h            |    7 ++++
 target-cris/translate.c      |   22 ++++++++++++
 target-i386/cpu.h            |    7 ++++
 target-i386/cpuid.c          |   79 ++++++++++++++++++++++++++++++++++++++++++
 target-m68k/cpu.h            |    9 +++++
 target-m68k/helper.c         |   23 ++++++++++++
 target-mips/cpu.h            |    7 ++++
 target-mips/translate.c      |    4 ++
 target-mips/translate_init.c |   19 ++++++++++
 target-ppc/cpu.h             |    7 ++++
 target-ppc/translate.c       |    4 ++
 target-ppc/translate_init.c  |   17 +++++++++
 target-sh4/cpu.h             |    8 ++++
 target-sh4/translate.c       |   23 ++++++++++++
 target-sparc/cpu.h           |    9 +++++
 target-sparc/helper.c        |   60 ++++++++++++++++++++++++++++++++
 21 files changed, 421 insertions(+), 0 deletions(-)
Markus Armbruster - June 26, 2010, 7:18 a.m.
"Daniel P. Berrange" <berrange@redhat.com> writes:

> This adds a new QMP command called 'query-cputypes' to allow
> for discovery of CPU types known to the QEMU binary. This is
> intended to relpace the need to parse '-cpu ?', '-cpu ?model'
> and '-cpu ?dump'
>
> Most targets have a simple structure listing just the CPU
> model names (and optionally a 'description'), with room for
> future expansion of extra attributes against each model
>
>   {
>       "cputypes": {
>           "models": [
>               {
>                   "name": "arm926"
>               },
>               {
>                   "name": "arm946"
>               },
>               {
>                   "name": "arm1026"
>               },
>               ....
>           ]
>       }
>   }
>
> The sparc and x86 targets have extra architecture specific
> metatadata. These are in keys 'x86info' and 'sparcinfo'
> against each CPU model dict. These keys are repeated at the
> top level to give data about all allowed feature names
>
> A trimmed example:
>
> {
>     "cputypes": {
>         "models": [
>             {
>                 "name": "n270",
>                 "description": "Intel(R) Atom(TM) CPU N270   @ 1.60GHz",
>                 "x86info": {
>                     "xlevel": 2147483658,
>                     "family": 6,
>                     "vendor": "",
>                     "level": 5,
>                     "model": 28,
>                     "stepping": 2,
>                     "features": {
>                         "ext_edx": [
>                             "lahf_lm"
>                         ],
>                         "edx": [
>                             "pbe",
>                             "tm",
>                             "ht",
>                             "ss",
>                             "sse2",
>                             ...
>                         ]
>                     }
>                 }
>             }
>         ],
>         "x86info": {
>             "features": {
>                 "ext_edx": [
>                     21,
>                     20,
>                     "nodeid_msr",
>                     "cvt16",
>                     17,
>                     "fma4",
>                     15,
>                     14,
>                     "wdt",
>                     ....
>                 ]
>             }
>         }
>     }
> }
>
> No mapping to the legacy readline monitor is provided


An alternative to arch-specific keys with equally arch-specific values
would be a arch-independent key with a discriminated union value.

  {
      "cputypes": {
          "models": [
              {
                  "name": "n270",
                  "description": "Intel(R) Atom(TM) CPU N270   @ 1.60GHz",
                  "arch-info": {
                      "arch": "x86",
                      "xlevel": 2147483658,
                      "family": 6,
                      ...

Dunno.

Patch

diff --git a/cpus.c b/cpus.c
index 8341f6c..0943f36 100644
--- a/cpus.c
+++ b/cpus.c
@@ -30,6 +30,7 @@ 
 #include "gdbstub.h"
 #include "dma.h"
 #include "kvm.h"
+#include "qjson.h"
 
 #include "cpus.h"
 
@@ -862,3 +863,80 @@  void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
     cpu_list(f, cpu_fprintf); /* deprecated */
 #endif
 }
+
+
+/**
+ * do_info_cpu_types()
+ *
+ * Return information about the CPU types known to this target
+ *
+ * The returned data is a QDict containing one mandatory key:
+ *
+ * - models: a QList of CPU models
+ *
+ * Each CPU model is a QDict containing the following keys
+ *
+ * - name: a short name for the CPU
+ * - description: a long verbose name for the CPU (optional)
+ *
+ *        {
+ *             "models": [
+ *                 {
+ *                     "name": "arm926"
+ *                 },
+ *                 {
+ *                     "name": "arm946"
+ *                 },
+ *                 {
+ *                     "name": "arm1026"
+ *                 },
+ *                 ....
+ *             ]
+ *         }
+ *
+ * Each CPU model can optionally contain architecture
+ * specific data. By convention this is provided in
+ * a key '${ARCH}info', eg i386 and x86_64 targets
+ * provide info about the CPU feature flags, and other
+ * attributes. A single CPU model entry for x86 will
+ * look like
+ *
+ *  {
+ *     "name": "n270",
+ *     "description": "Intel(R) Atom(TM) CPU N270   @ 1.60GHz",
+ *     "x86info": {
+ *         "xlevel": 2147483658,
+ *         "family": 6,
+ *         "vendor": "",
+ *         "level": 5,
+ *         "model": 28,
+ *         "stepping": 2,
+ *         "features": {
+ *             "ext_edx": [
+ *                 "lahf_lm"
+ *             ],
+ *             "edx": [
+ *                 "pbe",
+ *                 "tm",
+ *                 "ht",
+ *                 "ss",
+ *                 "sse2",
+ *                 ...
+ *             ]
+ *         }
+ *     }
+ *  }
+ *
+ * The architecture specific key can also be repeated at
+ * the top level QDict. For example to list the complete
+ * set of allowed features
+ */
+
+void do_info_cpu_types(Monitor *mon, QObject **data)
+{
+#if defined(arch_info_cpu_types)
+    arch_info_cpu_types(data);
+#else
+    *data = qobject_from_jsonf("{ 'models': [] }");
+#endif
+}
diff --git a/cpus.h b/cpus.h
index 774150a..5137866 100644
--- a/cpus.h
+++ b/cpus.h
@@ -18,5 +18,6 @@  void set_numa_modes(void);
 void set_cpu_log(const char *optarg);
 void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                const char *optarg);
+void do_info_cpu_types(Monitor *mon, QObject **data);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 13f70a0..2c4fb3f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -46,6 +46,7 @@ 
 #include "migration.h"
 #include "kvm.h"
 #include "acl.h"
+#include "cpus.h"
 #include "qint.h"
 #include "qfloat.h"
 #include "qlist.h"
@@ -2466,6 +2467,14 @@  static const mon_cmd_t info_cmds[] = {
         .mhandler.info_new = do_info_devices,
     },
     {
+        .name       = "cputypes",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the registered CPU models",
+        .user_print = monitor_user_noop,
+        .mhandler.info_new = do_info_cpu_types,
+    },
+    {
         .name       = "commands",
         .args_type  = "",
         .params     = "",
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f3d138d..3f884b7 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -28,6 +28,9 @@ 
 #include "cpu-defs.h"
 
 #include "softfloat.h"
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
 
 #define TARGET_HAS_ICE 1
 
@@ -354,6 +357,10 @@  static inline int arm_feature(CPUARMState *env, int feature)
 }
 
 void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#ifdef CONFIG_SOFTMMU
+void arm_info_cpu_types(QObject **data);
+#define arch_info_cpu_types arm_info_cpu_types
+#endif
 
 /* Interface between CPU and Interrupt controller.  */
 void armv7m_nvic_set_pending(void *opaque, int irq);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 63e5dc7..bba1530 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -8,6 +8,10 @@ 
 #include "helpers.h"
 #include "qemu-common.h"
 #include "host-utils.h"
+#ifdef CONFIG_SOFTMMU
+#include "qjson.h"
+#include "qlist.h"
+#endif
 #if !defined(CONFIG_USER_ONLY)
 #include "hw/loader.h"
 #endif
@@ -358,6 +362,23 @@  void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
     }
 }
 
+#ifdef CONFIG_SOFTMMU
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    int i;
+
+    for (i = 0; arm_cpu_names[i].name; i++) {
+	QObject *model = qobject_from_jsonf("{ 'name': %s }",
+					    arm_cpu_names[i].name);
+
+	qlist_append_obj(models, model);
+    }
+
+    *data = qobject_from_jsonf("{ 'models': %p }", models);
+}
+#endif
+
 /* return 0 if not found */
 static uint32_t cpu_arm_find_by_name(const char *name)
 {
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 063a240..b30c10e 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -25,6 +25,9 @@ 
 #define CPUState struct CPUCRISState
 
 #include "cpu-defs.h"
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
 
 #define TARGET_HAS_ICE 1
 
@@ -267,5 +270,9 @@  static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 
 #define cpu_list cris_cpu_list
 void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#ifdef CONFIG_SOFTMMU
+void cris_info_cpu_types(QObject **data);
+#define arch_info_cpu_types cris_info_cpu_types
+#endif
 
 #endif
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 6c1d9e0..0c326af 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -37,6 +37,10 @@ 
 #include "mmu.h"
 #include "crisv32-decode.h"
 #include "qemu-common.h"
+#ifdef CONFIG_SOFTMMU
+#include "qlist.h"
+#include "qjson.h"
+#endif
 
 #define GEN_HELPER 1
 #include "helper.h"
@@ -3468,6 +3472,24 @@  void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
     }
 }
 
+#ifdef CONFIG_SOFTMMU
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(cris_cores) ; i++) {
+	QObject *model = qobject_from_jsonf("{ 'name': %s }",
+					    cris_cores[i].name);
+
+	qlist_append_obj(models, model);
+    }
+
+    *data = qobject_from_jsonf("{ 'models': %p }", models);
+}
+#endif
+
+
 static uint32_t vr_by_name(const char *name)
 {
     unsigned int i;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 548ab80..1fa96b8 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -20,6 +20,9 @@ 
 #define CPU_I386_H
 
 #include "config.h"
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
 
 #ifdef TARGET_X86_64
 #define TARGET_LONG_BITS 64
@@ -725,6 +728,10 @@  int cpu_x86_exec(CPUX86State *s);
 void cpu_x86_close(CPUX86State *s);
 void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                    const char *optarg);
+#ifdef CONFIG_SOFTMMU
+void x86_info_cpu_types(QObject **data);
+#define arch_info_cpu_types x86_info_cpu_types
+#endif
 void x86_cpudef_setup(void);
 
 int cpu_get_pic_interrupt(CPUX86State *s);
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 7a11215..278f650 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -26,6 +26,12 @@ 
 
 #include "qemu-option.h"
 #include "qemu-config.h"
+#ifdef CONFIG_SOFTMMU
+#include "qstring.h"
+#include "qjson.h"
+#include "qint.h"
+#include "qdict.h"
+#endif
 
 /* feature flags taken from "Intel Processor Identification and the CPUID
  * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
@@ -784,6 +790,79 @@  void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
     }
 }
 
+
+#ifdef CONFIG_SOFTMMU
+static void qemu_caps_cpu_feature(QDict *features, const char *type,
+				  uint32_t fbits,
+				  const char **featureset)
+{
+    QList *set = qlist_new();
+    const char **p = &featureset[31];
+    char bit;
+
+    for (bit = 31; fbits ; --p, fbits &= ~(1 << bit), --bit) {
+        if (fbits & 1 << bit) {
+	    if (*p) {
+		qlist_append_obj(set, QOBJECT(qstring_from_str(*p)));
+	    } else {
+		qlist_append_obj(set, QOBJECT(qint_from_int(bit)));
+	    }
+	}
+    }
+    qdict_put_obj(features, type, QOBJECT(set));
+}
+
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    QDict *allfeatures = qdict_new();
+    x86_def_t *def;
+    char buf[256];
+
+    for (def = x86_defs; def; def = def->next) {
+	QObject *model;
+	QObject *x86info;
+	QDict *features = qdict_new();
+
+	memcpy(buf, &def->vendor1, sizeof (def->vendor1));
+	memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
+	memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
+	buf[12] = '\0';
+
+	qemu_caps_cpu_feature(features, "edx", def->features, feature_name);
+	qemu_caps_cpu_feature(features, "ecx", def->ext_features, ext_feature_name);
+	qemu_caps_cpu_feature(features, "ext_ecx", def->ext2_features, ext2_feature_name);
+	qemu_caps_cpu_feature(features, "ext_edx", def->ext3_features, ext3_feature_name);
+
+	x86info = qobject_from_jsonf("{ 'family': %d, 'model': %d, 'stepping': %d,"
+				     " 'level': %d, 'xlevel': %" PRId64 ", 'vendor': %s, 'features': %p }",
+				     def->family, def->model, def->stepping,
+				     def->level, (int64_t)def->xlevel, buf, features);
+
+	model = qobject_from_jsonf("{ 'name': %s, 'description': %s, 'x86info': %p }",
+				   def->name, def->model_id, x86info);
+
+	qlist_append_obj(models, model);
+    }
+    if (kvm_enabled()) {
+	/* XXX: fill in model + x86info fields based on host */
+	QObject *model = qobject_from_jsonf("{ 'name': %s }",
+					    "host");
+
+	qlist_append_obj(models, model);
+    }
+
+    qemu_caps_cpu_feature(allfeatures, "edx", ~0, feature_name);
+    qemu_caps_cpu_feature(allfeatures, "ecx", ~0, ext_feature_name);
+    qemu_caps_cpu_feature(allfeatures, "ext_ecx", ~0, ext2_feature_name);
+    qemu_caps_cpu_feature(allfeatures, "ext_edx", ~0, ext3_feature_name);
+
+    *data = qobject_from_jsonf("{ 'models': %p, 'x86info': { 'features': %p } }",
+			       models, allfeatures);
+}
+#endif
+
+
 int cpu_x86_register (CPUX86State *env, const char *cpu_model)
 {
     x86_def_t def1, *def = &def1;
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index b2f37ec..ac5f6bd 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -28,6 +28,10 @@ 
 
 #include "softfloat.h"
 
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
+
 #define MAX_QREGS 32
 
 #define TARGET_HAS_ICE 1
@@ -200,6 +204,11 @@  static inline int m68k_feature(CPUM68KState *env, int feature)
 
 void m68k_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
 
+#ifdef CONFIG_SOFTMMU
+void m68k_info_cpu_types(QObject **data);
+#define arch_info_cpu_types m68k_info_cpu_types
+#endif
+
 void register_m68k_insns (CPUM68KState *env);
 
 #ifdef CONFIG_USER_ONLY
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index b4ebb14..9de6722 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -26,6 +26,10 @@ 
 #include "exec-all.h"
 #include "qemu-common.h"
 #include "gdbstub.h"
+#ifdef CONFIG_SOFTMMU
+#include "qlist.h"
+#include "qjson.h"
+#endif
 
 #include "helpers.h"
 
@@ -62,6 +66,25 @@  void m68k_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
     }
 }
 
+
+#ifdef CONFIG_SOFTMMU
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    int i;
+
+    for (i = 0; m68k_cpu_defs[i].name; i++) {
+	QObject *model = qobject_from_jsonf("{ 'name': %s }",
+					    m68k_cpu_defs[i].name);
+
+	qlist_append_obj(models, model);
+    }
+
+    *data = qobject_from_jsonf("{ 'models': %p }", models);
+}
+#endif
+
+
 static int fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n)
 {
     if (n < 8) {
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 7285636..02bcadb 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -11,6 +11,9 @@ 
 #include "mips-defs.h"
 #include "cpu-defs.h"
 #include "softfloat.h"
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
 
 // uint_fast8_t and uint_fast16_t not in <sys/int_types.h>
 // XXX: move that elsewhere
@@ -496,6 +499,10 @@  void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
 #endif
 
 void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#ifdef CONFIG_SOFTMMU
+void mips_info_cpu_types(QObject **data);
+#define arch_info_cpu_types mips_info_cpu_types
+#endif
 
 #define cpu_init cpu_mips_init
 #define cpu_exec cpu_mips_exec
diff --git a/target-mips/translate.c b/target-mips/translate.c
index c95ecb1..0d9fd80 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -35,6 +35,10 @@ 
 #include "helper.h"
 #define GEN_HELPER 1
 #include "helper.h"
+#ifdef CONFIG_SOFTMMU
+#include "qlist.h"
+#include "qjson.h"
+#endif
 
 //#define MIPS_DEBUG_DISAS
 //#define MIPS_DEBUG_SIGN_EXTENSIONS
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index b79ed56..72ee283 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -479,6 +479,25 @@  void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
     }
 }
 
+
+#ifdef CONFIG_SOFTMMU
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(mips_defs); i++) {
+	QObject *model = qobject_from_jsonf("{ 'name': %s }",
+					    mips_defs[i].name);
+
+	qlist_append_obj(models, model);
+    }
+
+    *data = qobject_from_jsonf("{ 'models': %p }", models);
+}
+#endif
+
+
 #ifndef CONFIG_USER_ONLY
 static void no_mmu_init (CPUMIPSState *env, const mips_def_t *def)
 {
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2ad4486..69e0686 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -21,6 +21,9 @@ 
 
 #include "config.h"
 #include <inttypes.h>
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
 
 //#define PPC_EMULATE_32BITS_HYPV
 
@@ -758,6 +761,10 @@  void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value);
 void ppc_store_msr (CPUPPCState *env, target_ulong value);
 
 void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#ifdef CONFIG_SOFTMMU
+void ppc_info_cpu_types(QObject **data);
+#define arch_info_cpu_types ppc_info_cpu_types
+#endif
 
 const ppc_def_t *cpu_ppc_find_by_name (const char *name);
 int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 66e1c0d..8e6c9e3 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -28,6 +28,10 @@ 
 #include "tcg-op.h"
 #include "qemu-common.h"
 #include "host-utils.h"
+#ifdef CONFIG_SOFTMMU
+#include "qlist.h"
+#include "qjson.h"
+#endif
 
 #include "helper.h"
 #define GEN_HELPER 1
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index e8eadf4..4b4097a 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9764,3 +9764,20 @@  void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
                        ppc_defs[i].name, ppc_defs[i].pvr);
     }
 }
+
+#ifdef CONFIG_SOFTMMU
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
+	QObject *model = qobject_from_jsonf("{ 'name': %s }",
+					    ppc_defs[i].name);
+
+	qlist_append_obj(models, model);
+    }
+
+    *data = qobject_from_jsonf("{ 'models': %p }", models);
+}
+#endif
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index f8b1680..a0a6ed5 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -20,6 +20,9 @@ 
 #define _CPU_SH4_H
 
 #include "config.h"
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
 
 #define TARGET_LONG_BITS 32
 #define TARGET_HAS_ICE 1
@@ -169,6 +172,11 @@  int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
 void do_interrupt(CPUSH4State * env);
 
 void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#ifdef CONFIG_SOFTMMU
+void sh4_info_cpu_types(QObject **data);
+#define arch_info_cpu_types sh4_info_cpu_types
+#endif
+
 #if !defined(CONFIG_USER_ONLY)
 void cpu_sh4_invalidate_tlb(CPUSH4State *s);
 void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index d0d6c00..7d94ad2 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -31,6 +31,10 @@ 
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-common.h"
+#ifdef CONFIG_SOFTMMU
+#include "qlist.h"
+#include "qjson.h"
+#endif
 
 #include "helper.h"
 #define GEN_HELPER 1
@@ -265,6 +269,25 @@  void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
 	(*cpu_fprintf)(f, "%s\n", sh4_defs[i].name);
 }
 
+
+#ifdef CONFIG_SOFTMMU
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(sh4_defs); i++) {
+	QObject *model = qobject_from_jsonf("{ 'name': %s }",
+					    sh4_defs[i].name);
+
+	qlist_append_obj(models, model);
+    }
+
+    *data = qobject_from_jsonf("{ 'models': %p }", models);
+}
+#endif
+
+
 static void cpu_sh4_register(CPUSH4State *env, const sh4_def_t *def)
 {
     env->pvr = def->pvr;
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 8f0484b..7b433ed 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -27,6 +27,10 @@ 
 
 #include "softfloat.h"
 
+#ifdef CONFIG_SOFTMMU
+#include "qobject.h"
+#endif
+
 #define TARGET_HAS_ICE 1
 
 #if !defined(TARGET_SPARC64)
@@ -444,6 +448,11 @@  CPUSPARCState *cpu_sparc_init(const char *cpu_model);
 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
 void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
                                                  ...));
+#ifdef CONFIG_SOFTMMU
+void sparc_info_cpu_types(QObject **data);
+#define arch_info_cpu_types sparc_info_cpu_types
+#endif
+
 void cpu_lock(void);
 void cpu_unlock(void);
 int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index aa1fd63..15b4cc2 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -26,6 +26,11 @@ 
 #include "cpu.h"
 #include "exec-all.h"
 #include "qemu-common.h"
+#ifdef CONFIG_SOFTMMU
+#include "qlist.h"
+#include "qdict.h"
+#include "qjson.h"
+#endif
 
 //#define DEBUG_MMU
 //#define DEBUG_FEATURES
@@ -1479,6 +1484,61 @@  void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
                    "fpu_version mmu_version nwindows\n");
 }
 
+
+#ifdef CONFIG_SOFTMMU
+static void cpu_type_feature_info(QDict *info,
+				  const char *name,
+				  uint32_t bits)
+{
+    QList *features = qlist_new();
+    unsigned int i;
+
+    qdict_put_obj(info, name, QOBJECT(features));
+
+    for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+        if (feature_name[i] && (bits & (1 << i))) {
+	    qlist_append_obj(features, QOBJECT(qstring_from_str(feature_name[i])));
+        }
+    }
+}
+
+void arch_info_cpu_types(QObject **data)
+{
+    QList *models = qlist_new();
+    QDict *allsparcinfo = qdict_new();
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+	QObject *model;
+	QDict *sparcinfo = qdict_new();
+
+	cpu_type_feature_info(sparcinfo, "features",
+			      sparc_defs[i].features);
+
+	model = qobject_from_jsonf("{ 'name': %s, 'sparcinfo': %p, "
+				   " 'iu_version': %" PRId64 ", "
+				   " 'fpu_version': %" PRId64 ", "
+				   " 'mmu_version': %" PRId64 ", "
+				   " 'nwindows': %d }",
+				   sparc_defs[i].name, sparcinfo,
+				   (uint64_t)sparc_defs[i].iu_version,
+				   (uint64_t)sparc_defs[i].fpu_version,
+				   (uint64_t)sparc_defs[i].mmu_version,
+				   sparc_defs[i].nwindows);
+
+	qlist_append_obj(models, model);
+    }
+
+    cpu_type_feature_info(allsparcinfo, "features",
+			  ~0);
+    cpu_type_feature_info(allsparcinfo, "deffeatures",
+			  CPU_DEFAULT_FEATURES);
+
+    *data = qobject_from_jsonf("{ 'models': %p, 'sparcinfo': %p }",
+			       models, allsparcinfo);
+}
+#endif
+
 static void cpu_print_cc(FILE *f,
                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                          uint32_t cc)