Merge remote-tracking branch 'afaerber/qom-cpu' into staging
# By Eduardo Habkost (6) and others # Via Andreas Färber * afaerber/qom-cpu: target-i386: n270 can MOVBE target-i386: Introduce generic CPUID feature compat function target-i386: Change CPUID model of 486 to 8 target-i386: Emulate X86CPU subclasses for global properties qdev: Introduce qdev_prop_set_globals_for_type() qdev: Let qdev_prop_parse() pass through Error target-i386: Add "filtered-features" property to X86CPU target-i386: Introduce X86CPU::filtered_features field target-i386: Add "feature-words" property to X86CPU target-i386: Use FeatureWord loop on filter_features_for_kvm() target-i386: Add ECX information to FeatureWordInfo
This commit is contained in:
commit
fd8192a5a8
@ -79,10 +79,15 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
|
|||||||
######################################################################
|
######################################################################
|
||||||
# qapi
|
# 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
|
common-obj-y += qmp.o hmp.o
|
||||||
endif
|
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
|
# Target-independent parts used in system and user emulation
|
||||||
common-obj-y += qemu-log.o
|
common-obj-y += qemu-log.o
|
||||||
|
@ -986,25 +986,18 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
|
void qdev_prop_parse(DeviceState *dev, const char *name, const char *value,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
char *legacy_name;
|
char *legacy_name;
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
legacy_name = g_strdup_printf("legacy-%s", name);
|
legacy_name = g_strdup_printf("legacy-%s", name);
|
||||||
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
|
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
|
||||||
object_property_parse(OBJECT(dev), value, legacy_name, &err);
|
object_property_parse(OBJECT(dev), value, legacy_name, errp);
|
||||||
} else {
|
} else {
|
||||||
object_property_parse(OBJECT(dev), value, name, &err);
|
object_property_parse(OBJECT(dev), value, name, errp);
|
||||||
}
|
}
|
||||||
g_free(legacy_name);
|
g_free(legacy_name);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
qerror_report_err(err);
|
|
||||||
error_free(err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
|
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
|
||||||
@ -1106,19 +1099,37 @@ void qdev_prop_register_global_list(GlobalProperty *props)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_prop_set_globals(DeviceState *dev)
|
void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
GlobalProperty *prop;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(prop, &global_props, next) {
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
if (strcmp(typename, prop->driver) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
qdev_prop_parse(dev, prop->property, prop->value, &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void qdev_prop_set_globals(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
ObjectClass *class = object_get_class(OBJECT(dev));
|
ObjectClass *class = object_get_class(OBJECT(dev));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
GlobalProperty *prop;
|
Error *err = NULL;
|
||||||
QTAILQ_FOREACH(prop, &global_props, next) {
|
|
||||||
if (strcmp(object_class_get_name(class), prop->driver) != 0) {
|
qdev_prop_set_globals_for_type(dev, object_class_get_name(class),
|
||||||
continue;
|
&err);
|
||||||
}
|
if (err != NULL) {
|
||||||
if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
|
error_propagate(errp, err);
|
||||||
exit(1);
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
class = object_class_get_parent(class);
|
class = object_class_get_parent(class);
|
||||||
} while (class);
|
} while (class);
|
||||||
|
@ -752,7 +752,12 @@ static void device_initfn(Object *obj)
|
|||||||
}
|
}
|
||||||
class = object_class_get_parent(class);
|
class = object_class_get_parent(class);
|
||||||
} while (class != object_class_by_name(TYPE_DEVICE));
|
} while (class != object_class_by_name(TYPE_DEVICE));
|
||||||
qdev_prop_set_globals(dev);
|
qdev_prop_set_globals(dev, &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
qerror_report_err(err);
|
||||||
|
error_free(err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
||||||
(Object **)&dev->parent_bus, &err);
|
(Object **)&dev->parent_bus, &err);
|
||||||
|
@ -250,6 +250,7 @@ static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
|
|||||||
{
|
{
|
||||||
pc_sysfw_flash_vs_rom_bug_compatible = true;
|
pc_sysfw_flash_vs_rom_bug_compatible = true;
|
||||||
has_pvpanic = false;
|
has_pvpanic = false;
|
||||||
|
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
|
||||||
pc_init_pci(args);
|
pc_init_pci(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +212,7 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
|
|||||||
{
|
{
|
||||||
pc_sysfw_flash_vs_rom_bug_compatible = true;
|
pc_sysfw_flash_vs_rom_bug_compatible = true;
|
||||||
has_pvpanic = false;
|
has_pvpanic = false;
|
||||||
|
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
|
||||||
pc_q35_init(args);
|
pc_q35_init(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +242,10 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
|
|||||||
.driver = "pc-sysfw",\
|
.driver = "pc-sysfw",\
|
||||||
.property = "rom_only",\
|
.property = "rom_only",\
|
||||||
.value = stringify(0),\
|
.value = stringify(0),\
|
||||||
|
},{\
|
||||||
|
.driver = "486-" TYPE_X86_CPU,\
|
||||||
|
.property = "model",\
|
||||||
|
.value = stringify(0),\
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -148,7 +148,8 @@ extern PropertyInfo qdev_prop_arraylen;
|
|||||||
|
|
||||||
/* Set properties between creation and init. */
|
/* Set properties between creation and init. */
|
||||||
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
|
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
|
||||||
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
|
void qdev_prop_parse(DeviceState *dev, const char *name, const char *value,
|
||||||
|
Error **errp);
|
||||||
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
|
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
|
||||||
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
|
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
|
||||||
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
|
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
|
||||||
@ -167,7 +168,9 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
|
|||||||
|
|
||||||
void qdev_prop_register_global(GlobalProperty *prop);
|
void qdev_prop_register_global(GlobalProperty *prop);
|
||||||
void qdev_prop_register_global_list(GlobalProperty *props);
|
void qdev_prop_register_global_list(GlobalProperty *props);
|
||||||
void qdev_prop_set_globals(DeviceState *dev);
|
void qdev_prop_set_globals(DeviceState *dev, Error **errp);
|
||||||
|
void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
|
||||||
|
Error **errp);
|
||||||
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
||||||
Property *prop, const char *value);
|
Property *prop, const char *value);
|
||||||
|
|
||||||
|
@ -3587,3 +3587,35 @@
|
|||||||
##
|
##
|
||||||
{'command': 'query-command-line-options', 'data': { '*option': 'str' },
|
{'command': 'query-command-line-options', 'data': { '*option': 'str' },
|
||||||
'returns': ['CommandLineOptionInfo'] }
|
'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' } }
|
||||||
|
@ -105,13 +105,17 @@ static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
|
|||||||
static int set_property(const char *name, const char *value, void *opaque)
|
static int set_property(const char *name, const char *value, void *opaque)
|
||||||
{
|
{
|
||||||
DeviceState *dev = opaque;
|
DeviceState *dev = opaque;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
if (strcmp(name, "driver") == 0)
|
if (strcmp(name, "driver") == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (strcmp(name, "bus") == 0)
|
if (strcmp(name, "bus") == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (qdev_prop_parse(dev, name, value) == -1) {
|
qdev_prop_parse(dev, name, value, &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
qerror_report_err(err);
|
||||||
|
error_free(err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -65,6 +65,9 @@ typedef struct X86CPU {
|
|||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
CPUX86State env;
|
CPUX86State env;
|
||||||
|
|
||||||
|
/* Features that were filtered out because of missing host capabilities */
|
||||||
|
uint32_t filtered_features[FEATURE_WORDS];
|
||||||
} X86CPU;
|
} X86CPU;
|
||||||
|
|
||||||
static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
|
static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
|
|
||||||
|
#include "qapi-types.h"
|
||||||
|
#include "qapi-visit.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "sysemu/arch_init.h"
|
#include "sysemu/arch_init.h"
|
||||||
|
|
||||||
@ -152,8 +154,10 @@ static const char *cpuid_7_0_ebx_feature_name[] = {
|
|||||||
|
|
||||||
typedef struct FeatureWordInfo {
|
typedef struct FeatureWordInfo {
|
||||||
const char **feat_names;
|
const char **feat_names;
|
||||||
uint32_t cpuid_eax; /* Input EAX for CPUID */
|
uint32_t cpuid_eax; /* Input EAX for CPUID */
|
||||||
int cpuid_reg; /* R_* register constant */
|
bool cpuid_needs_ecx; /* CPUID instruction uses ECX as input */
|
||||||
|
uint32_t cpuid_ecx; /* Input ECX value for CPUID */
|
||||||
|
int cpuid_reg; /* output register (R_* constant) */
|
||||||
} FeatureWordInfo;
|
} FeatureWordInfo;
|
||||||
|
|
||||||
static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
||||||
@ -187,27 +191,40 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||||||
},
|
},
|
||||||
[FEAT_7_0_EBX] = {
|
[FEAT_7_0_EBX] = {
|
||||||
.feat_names = cpuid_7_0_ebx_feature_name,
|
.feat_names = cpuid_7_0_ebx_feature_name,
|
||||||
.cpuid_eax = 7, .cpuid_reg = R_EBX,
|
.cpuid_eax = 7,
|
||||||
|
.cpuid_needs_ecx = true, .cpuid_ecx = 0,
|
||||||
|
.cpuid_reg = R_EBX,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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)
|
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) {
|
if (reg > CPU_NB_REGS32) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return reg_names[reg];
|
return x86_reg_info_32[reg].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* collects per-function cpuid data
|
/* collects per-function cpuid data
|
||||||
@ -571,7 +588,7 @@ static x86_def_t builtin_x86_defs[] = {
|
|||||||
.level = 1,
|
.level = 1,
|
||||||
.vendor = CPUID_VENDOR_INTEL,
|
.vendor = CPUID_VENDOR_INTEL,
|
||||||
.family = 4,
|
.family = 4,
|
||||||
.model = 0,
|
.model = 8,
|
||||||
.stepping = 0,
|
.stepping = 0,
|
||||||
.features[FEAT_1_EDX] =
|
.features[FEAT_1_EDX] =
|
||||||
I486_FEATURES,
|
I486_FEATURES,
|
||||||
@ -640,7 +657,8 @@ static x86_def_t builtin_x86_defs[] = {
|
|||||||
/* Some CPUs got no CPUID_SEP */
|
/* Some CPUs got no CPUID_SEP */
|
||||||
.features[FEAT_1_ECX] =
|
.features[FEAT_1_ECX] =
|
||||||
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
|
||||||
CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR,
|
CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR |
|
||||||
|
CPUID_EXT_MOVBE,
|
||||||
.features[FEAT_8000_0001_EDX] =
|
.features[FEAT_8000_0001_EDX] =
|
||||||
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
|
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
|
||||||
CPUID_EXT2_NX,
|
CPUID_EXT2_NX,
|
||||||
@ -954,6 +972,32 @@ static x86_def_t builtin_x86_defs[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* x86_cpu_compat_set_features:
|
||||||
|
* @cpu_model: CPU model name to be changed. If NULL, all CPU models are changed
|
||||||
|
* @w: Identifies the feature word to be changed.
|
||||||
|
* @feat_add: Feature bits to be added to feature word
|
||||||
|
* @feat_remove: Feature bits to be removed from feature word
|
||||||
|
*
|
||||||
|
* Change CPU model feature bits for compatibility.
|
||||||
|
*
|
||||||
|
* This function may be used by machine-type compatibility functions
|
||||||
|
* to enable or disable feature bits on specific CPU models.
|
||||||
|
*/
|
||||||
|
void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
|
||||||
|
uint32_t feat_add, uint32_t feat_remove)
|
||||||
|
{
|
||||||
|
x86_def_t *def;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
||||||
|
def = &builtin_x86_defs[i];
|
||||||
|
if (!cpu_model || !strcmp(cpu_model, def->name)) {
|
||||||
|
def->features[w] |= feat_add;
|
||||||
|
def->features[w] &= ~feat_remove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KVM
|
#ifdef CONFIG_KVM
|
||||||
static int cpu_x86_fill_model_id(char *str)
|
static int cpu_x86_fill_model_id(char *str)
|
||||||
{
|
{
|
||||||
@ -1401,6 +1445,36 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
|
|||||||
cpu->env.cpuid_apic_id = value;
|
cpu->env.cpuid_apic_id = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generic getter for "feature-words" and "filtered-features" properties */
|
||||||
|
static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque,
|
||||||
|
const char *name, Error **errp)
|
||||||
|
{
|
||||||
|
uint32_t *array = (uint32_t *)opaque;
|
||||||
|
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 = array[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)
|
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
|
||||||
{
|
{
|
||||||
x86_def_t *def;
|
x86_def_t *def;
|
||||||
@ -1647,24 +1721,17 @@ static void filter_features_for_kvm(X86CPU *cpu)
|
|||||||
{
|
{
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
KVMState *s = kvm_state;
|
KVMState *s = kvm_state;
|
||||||
|
FeatureWord w;
|
||||||
|
|
||||||
env->features[FEAT_1_EDX] &=
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||||
kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
|
FeatureWordInfo *wi = &feature_word_info[w];
|
||||||
env->features[FEAT_1_ECX] &=
|
uint32_t host_feat = kvm_arch_get_supported_cpuid(s, wi->cpuid_eax,
|
||||||
kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX);
|
wi->cpuid_ecx,
|
||||||
env->features[FEAT_8000_0001_EDX] &=
|
wi->cpuid_reg);
|
||||||
kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
|
uint32_t requested_features = env->features[w];
|
||||||
env->features[FEAT_8000_0001_ECX] &=
|
env->features[w] &= host_feat;
|
||||||
kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
|
cpu->filtered_features[w] = requested_features & ~env->features[w];
|
||||||
env->features[FEAT_SVM] &=
|
}
|
||||||
kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
|
|
||||||
env->features[FEAT_7_0_EBX] &=
|
|
||||||
kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX);
|
|
||||||
env->features[FEAT_KVM] &=
|
|
||||||
kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
|
|
||||||
env->features[FEAT_C000_0001_EDX] &=
|
|
||||||
kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1711,6 +1778,7 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
|
|||||||
CPUX86State *env;
|
CPUX86State *env;
|
||||||
gchar **model_pieces;
|
gchar **model_pieces;
|
||||||
char *name, *features;
|
char *name, *features;
|
||||||
|
char *typename;
|
||||||
Error *error = NULL;
|
Error *error = NULL;
|
||||||
|
|
||||||
model_pieces = g_strsplit(cpu_model, ",", 2);
|
model_pieces = g_strsplit(cpu_model, ",", 2);
|
||||||
@ -1738,6 +1806,14 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Emulate per-model subclasses for global properties */
|
||||||
|
typename = g_strdup_printf("%s-" TYPE_X86_CPU, name);
|
||||||
|
qdev_prop_set_globals_for_type(DEVICE(cpu), typename, &error);
|
||||||
|
g_free(typename);
|
||||||
|
if (error) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
cpu_x86_parse_featurestr(cpu, features, &error);
|
cpu_x86_parse_featurestr(cpu, features, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
goto out;
|
goto out;
|
||||||
@ -2402,6 +2478,12 @@ static void x86_cpu_initfn(Object *obj)
|
|||||||
object_property_add(obj, "apic-id", "int",
|
object_property_add(obj, "apic-id", "int",
|
||||||
x86_cpuid_get_apic_id,
|
x86_cpuid_get_apic_id,
|
||||||
x86_cpuid_set_apic_id, NULL, NULL, NULL);
|
x86_cpuid_set_apic_id, NULL, NULL, NULL);
|
||||||
|
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
|
||||||
|
x86_cpu_get_feature_words,
|
||||||
|
NULL, NULL, (void *)env->features, NULL);
|
||||||
|
object_property_add(obj, "filtered-features", "X86CPUFeatureWordInfo",
|
||||||
|
x86_cpu_get_feature_words,
|
||||||
|
NULL, NULL, (void *)cpu->filtered_features, NULL);
|
||||||
|
|
||||||
env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
|
env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
|
||||||
|
|
||||||
|
@ -1255,6 +1255,10 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
|
|||||||
|
|
||||||
void disable_kvm_pv_eoi(void);
|
void disable_kvm_pv_eoi(void);
|
||||||
|
|
||||||
|
void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
|
||||||
|
uint32_t feat_add, uint32_t feat_remove);
|
||||||
|
|
||||||
|
|
||||||
/* Return name of 32-bit register, from a R_* constant */
|
/* Return name of 32-bit register, from a R_* constant */
|
||||||
const char *get_register_name_32(unsigned int reg);
|
const char *get_register_name_32(unsigned int reg);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user