Skip to content

Commit

Permalink
target-i386: Add "feature-words" property to X86CPU
Browse files Browse the repository at this point in the history
This property will be useful for libvirt, as libvirt already has logic
based on low-level feature bits (not feature names), so it will be
really easy to convert the current libvirt logic to something using the
"feature-words" property.

The property will have two main use cases:
 - Checking host capabilities, by checking the features of the "host"
   CPU model
 - Checking which features are enabled on each CPU model

Example output:

  $ ./QMP/qmp --path=/tmp/m \
    qom-get --path=/machine/icc-bridge/icc/child[0] \
            --property=feature-words
  item[0].cpuid-register: EDX
  item[0].cpuid-input-eax: 2147483658
  item[0].features: 0
  item[1].cpuid-register: EAX
  item[1].cpuid-input-eax: 1073741825
  item[1].features: 0
  item[2].cpuid-register: EDX
  item[2].cpuid-input-eax: 3221225473
  item[2].features: 0
  item[3].cpuid-register: ECX
  item[3].cpuid-input-eax: 2147483649
  item[3].features: 101
  item[4].cpuid-register: EDX
  item[4].cpuid-input-eax: 2147483649
  item[4].features: 563346425
  item[5].cpuid-register: EBX
  item[5].cpuid-input-eax: 7
  item[5].features: 0
  item[5].cpuid-input-ecx: 0
  item[6].cpuid-register: ECX
  item[6].cpuid-input-eax: 1
  item[6].features: 2155880449
  item[7].cpuid-register: EDX
  item[7].cpuid-input-eax: 1
  item[7].features: 126614521

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
  • Loading branch information
ehabkost authored and afaerber committed May 6, 2013
1 parent bd87d2a commit 8e8aba5
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 13 deletions.
7 changes: 6 additions & 1 deletion Makefile.objs
Expand Up @@ -79,10 +79,15 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
######################################################################
# qapi

common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
common-obj-y += qmp-marshal.o
common-obj-y += qmp.o hmp.o
endif

######################################################################
# some qapi visitors are used by both system and user emulation:

common-obj-y += qapi-visit.o qapi-types.o

#######################################################################
# Target-independent parts used in system and user emulation
common-obj-y += qemu-log.o
Expand Down
32 changes: 32 additions & 0 deletions qapi-schema.json
Expand Up @@ -3587,3 +3587,35 @@
##
{'command': 'query-command-line-options', 'data': { '*option': 'str' },
'returns': ['CommandLineOptionInfo'] }

##
# @X86CPURegister32
#
# A X86 32-bit register
#
# Since: 1.5
##
{ 'enum': 'X86CPURegister32',
'data': [ 'EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI' ] }

##
# @X86CPUFeatureWordInfo
#
# Information about a X86 CPU feature word
#
# @cpuid-input-eax: Input EAX value for CPUID instruction for that feature word
#
# @cpuid-input-ecx: #optional Input ECX value for CPUID instruction for that
# feature word
#
# @cpuid-register: Output register containing the feature bits
#
# @features: value of output register, containing the feature bits
#
# Since: 1.5
##
{ 'type': 'X86CPUFeatureWordInfo',
'data': { 'cpuid-input-eax': 'int',
'*cpuid-input-ecx': 'int',
'cpuid-register': 'X86CPURegister32',
'features': 'int' } }
70 changes: 58 additions & 12 deletions target-i386/cpu.c
Expand Up @@ -30,6 +30,8 @@
#include "qemu/config-file.h"
#include "qapi/qmp/qerror.h"

#include "qapi-types.h"
#include "qapi-visit.h"
#include "qapi/visitor.h"
#include "sysemu/arch_init.h"

Expand Down Expand Up @@ -195,23 +197,34 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
},
};

typedef struct X86RegisterInfo32 {
/* Name of register */
const char *name;
/* QAPI enum value register */
X86CPURegister32 qapi_enum;
} X86RegisterInfo32;

#define REGISTER(reg) \
[R_##reg] = { .name = #reg, .qapi_enum = X86_C_P_U_REGISTER32_##reg }
X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
REGISTER(EAX),
REGISTER(ECX),
REGISTER(EDX),
REGISTER(EBX),
REGISTER(ESP),
REGISTER(EBP),
REGISTER(ESI),
REGISTER(EDI),
};
#undef REGISTER


const char *get_register_name_32(unsigned int reg)
{
static const char *reg_names[CPU_NB_REGS32] = {
[R_EAX] = "EAX",
[R_ECX] = "ECX",
[R_EDX] = "EDX",
[R_EBX] = "EBX",
[R_ESP] = "ESP",
[R_EBP] = "EBP",
[R_ESI] = "ESI",
[R_EDI] = "EDI",
};

if (reg > CPU_NB_REGS32) {
return NULL;
}
return reg_names[reg];
return x86_reg_info_32[reg].name;
}

/* collects per-function cpuid data
Expand Down Expand Up @@ -1405,6 +1418,36 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
cpu->env.cpuid_apic_id = value;
}

static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
FeatureWord w;
Error *err = NULL;
X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { };
X86CPUFeatureWordInfoList *list = NULL;

for (w = 0; w < FEATURE_WORDS; w++) {
FeatureWordInfo *wi = &feature_word_info[w];
X86CPUFeatureWordInfo *qwi = &word_infos[w];
qwi->cpuid_input_eax = wi->cpuid_eax;
qwi->has_cpuid_input_ecx = wi->cpuid_needs_ecx;
qwi->cpuid_input_ecx = wi->cpuid_ecx;
qwi->cpuid_register = x86_reg_info_32[wi->cpuid_reg].qapi_enum;
qwi->features = env->features[w];

/* List will be in reverse order, but order shouldn't matter */
list_entries[w].next = list;
list_entries[w].value = &word_infos[w];
list = &list_entries[w];
}

visit_type_X86CPUFeatureWordInfoList(v, &list, "feature-words", &err);
error_propagate(errp, err);
}

static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
{
x86_def_t *def;
Expand Down Expand Up @@ -2396,6 +2439,9 @@ static void x86_cpu_initfn(Object *obj)
object_property_add(obj, "apic-id", "int",
x86_cpuid_get_apic_id,
x86_cpuid_set_apic_id, NULL, NULL, NULL);
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
x86_cpu_get_feature_words,
NULL, NULL, NULL, NULL);

env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);

Expand Down

0 comments on commit 8e8aba5

Please sign in to comment.