@@ -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
+}
@@ -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
@@ -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 = "",
@@ -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);
@@ -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)
{
@@ -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
@@ -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;
@@ -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);
@@ -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;
@@ -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
@@ -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) {
@@ -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
@@ -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
@@ -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)
{
@@ -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);
@@ -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
@@ -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
@@ -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,
@@ -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;
@@ -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,
@@ -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)
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(-)