Commit 8e8aba50 authored by Eduardo Habkost's avatar Eduardo Habkost Committed by Andreas Färber
Browse files

target-i386: Add "feature-words" property to X86CPU



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: default avatarEduardo Habkost <ehabkost@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Signed-off-by: default avatarAndreas Färber <afaerber@suse.de>
parent bd87d2a2
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -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
+32 −0
Original line number Diff line number Diff line
@@ -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' } }
+58 −12
Original line number Diff line number Diff line
@@ -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"

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

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",
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)
{
    if (reg > CPU_NB_REGS32) {
        return NULL;
    }
    return reg_names[reg];
    return x86_reg_info_32[reg].name;
}

/* collects per-function cpuid data
@@ -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;
@@ -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);