mirror of https://github.com/xemu-project/xemu.git
x86 queue, 2017-02-27
"-cpu max" and query-cpu-model-expansion support for x86. This should be the last x86 pull request before 2.9 soft freeze. -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJYtFKvAAoJECgHk2+YTcWmyCwQAJEBM8NdOmN14yA3qTiTs0Kd D/3VWSxtu9t41g39+yho70c+ZnpqGW28/WbY7E4ovAPRIoUI/pmKACY42k+WrTmK MIBMesp1YnkxhwrFW9CwgqiUV8nr5ZMlzW/pQU/GaXbcH+7KfObeI93iGhtGjWvi 4nNvrK7b5mz2wPU6s1j+Bz2mp0CMd/sktmiH93tyWU+KgU7NXvMDPInVkfvBMvZN 5D6JLIeKxrndbaaUgvGbR4SUUmRs8TZFYfEbOdkkjIqh7MAKVKCCipFaxWIEfndr bs1MDmw6uIUaI55JuWaXb//BkS+jai1dmn+ZEzMoisetlheSwR8cEStFJBxcm/7n WQfxUd6TuNJ9PC1FIvb/OHUCGvzb+vtbEYAMmvCv8BVMnMivN7WNliu3rNVRgWBK OHClBPdgwoIx2cGt6ic1rvxHxcpjeJ/YXBzL/JbBkblckpxbNRcW1NRTZKHIe3vr JcPMEoP8g5d9ZHOG0WqBhKtJ3vUrxF3xqBKuR1Ha7QWpyKe9YF+RKrIA9dZkhLy0 Jh0fPZn2PmQrbLuZTC1u7Sgp22Duy7RcfJ7SikR+uhMLtkvToqu3ywLteW6Ta1by oinb2UYMazwpAKKDcab4GdNJHPOuhnDw58osBVTyBiiN1tJjH+BhnVV4bYJVpaHI MJIx5QvwqocSO0qoDZxo =KPbC -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ehabkost/tags/x86-pull-request' into staging x86 queue, 2017-02-27 "-cpu max" and query-cpu-model-expansion support for x86. This should be the last x86 pull request before 2.9 soft freeze. # gpg: Signature made Mon 27 Feb 2017 16:24:15 GMT # gpg: using RSA key 0x2807936F984DC5A6 # gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>" # Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF D1AA 2807 936F 984D C5A6 * remotes/ehabkost/tags/x86-pull-request: i386: Improve query-cpu-model-expansion full mode i386: Implement query-cpu-model-expansion QMP command i386: Define static "base" CPU model i386: Don't set CPUClass::cpu_def on "max" model i386: Make "max" model not use any host CPUID info on TCG i386: Create "max" CPU model qapi-schema: Comment about full expansion of non-migration-safe models i386: Reorganize and document CPUID initialization steps i386: Rename X86CPU::host_features to X86CPU::max_features i386: Add ordering field to CPUClass i386: Unset cannot_destroy_with_object_finalize_yet on "host" model Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
666095c852
|
@ -984,8 +984,10 @@ static void qmp_unregister_commands_hack(void)
|
||||||
#ifndef TARGET_ARM
|
#ifndef TARGET_ARM
|
||||||
qmp_unregister_command("query-gic-capabilities");
|
qmp_unregister_command("query-gic-capabilities");
|
||||||
#endif
|
#endif
|
||||||
#if !defined(TARGET_S390X)
|
#if !defined(TARGET_S390X) && !defined(TARGET_I386)
|
||||||
qmp_unregister_command("query-cpu-model-expansion");
|
qmp_unregister_command("query-cpu-model-expansion");
|
||||||
|
#endif
|
||||||
|
#if !defined(TARGET_S390X)
|
||||||
qmp_unregister_command("query-cpu-model-baseline");
|
qmp_unregister_command("query-cpu-model-baseline");
|
||||||
qmp_unregister_command("query-cpu-model-comparison");
|
qmp_unregister_command("query-cpu-model-comparison");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4274,6 +4274,15 @@
|
||||||
# migration-safe, but allows tooling to get an insight and work with
|
# migration-safe, but allows tooling to get an insight and work with
|
||||||
# model details.
|
# model details.
|
||||||
#
|
#
|
||||||
|
# Note: When a non-migration-safe CPU model is expanded in static mode, some
|
||||||
|
# features enabled by the CPU model may be omitted, because they can't be
|
||||||
|
# implemented by a static CPU model definition (e.g. cache info passthrough and
|
||||||
|
# PMU passthrough in x86). If you need an accurate representation of the
|
||||||
|
# features enabled by a non-migration-safe CPU model, use @full. If you need a
|
||||||
|
# static representation that will keep ABI compatibility even when changing QEMU
|
||||||
|
# version or machine-type, use @static (but keep in mind that some features may
|
||||||
|
# be omitted).
|
||||||
|
#
|
||||||
# Since: 2.8.0
|
# Since: 2.8.0
|
||||||
##
|
##
|
||||||
{ 'enum': 'CpuModelExpansionType',
|
{ 'enum': 'CpuModelExpansionType',
|
||||||
|
|
|
@ -48,7 +48,9 @@ typedef struct X86CPUDefinition X86CPUDefinition;
|
||||||
* X86CPUClass:
|
* X86CPUClass:
|
||||||
* @cpu_def: CPU model definition
|
* @cpu_def: CPU model definition
|
||||||
* @kvm_required: Whether CPU model requires KVM to be enabled.
|
* @kvm_required: Whether CPU model requires KVM to be enabled.
|
||||||
|
* @ordering: Ordering on the "-cpu help" CPU model list.
|
||||||
* @migration_safe: See CpuDefinitionInfo::migration_safe
|
* @migration_safe: See CpuDefinitionInfo::migration_safe
|
||||||
|
* @static_model: See CpuDefinitionInfo::static
|
||||||
* @parent_realize: The parent class' realize handler.
|
* @parent_realize: The parent class' realize handler.
|
||||||
* @parent_reset: The parent class' reset handler.
|
* @parent_reset: The parent class' reset handler.
|
||||||
*
|
*
|
||||||
|
@ -59,11 +61,15 @@ typedef struct X86CPUClass {
|
||||||
CPUClass parent_class;
|
CPUClass parent_class;
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
/* Should be eventually replaced by subclass-specific property defaults. */
|
/* CPU definition, automatically loaded by instance_init if not NULL.
|
||||||
|
* Should be eventually replaced by subclass-specific property defaults.
|
||||||
|
*/
|
||||||
X86CPUDefinition *cpu_def;
|
X86CPUDefinition *cpu_def;
|
||||||
|
|
||||||
bool kvm_required;
|
bool kvm_required;
|
||||||
|
int ordering;
|
||||||
bool migration_safe;
|
bool migration_safe;
|
||||||
|
bool static_model;
|
||||||
|
|
||||||
/* Optional description of CPU model.
|
/* Optional description of CPU model.
|
||||||
* If unavailable, cpu_def->model_id is used */
|
* If unavailable, cpu_def->model_id is used */
|
||||||
|
|
|
@ -29,10 +29,16 @@
|
||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
|
#include "qapi/qmp/qstring.h"
|
||||||
|
#include "qapi/qmp/qdict.h"
|
||||||
|
#include "qapi/qmp/qbool.h"
|
||||||
|
#include "qapi/qmp/qint.h"
|
||||||
|
#include "qapi/qmp/qfloat.h"
|
||||||
|
|
||||||
#include "qapi-types.h"
|
#include "qapi-types.h"
|
||||||
#include "qapi-visit.h"
|
#include "qapi-visit.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
|
#include "qom/qom-qobject.h"
|
||||||
#include "sysemu/arch_init.h"
|
#include "sysemu/arch_init.h"
|
||||||
|
|
||||||
#if defined(CONFIG_KVM)
|
#if defined(CONFIG_KVM)
|
||||||
|
@ -1503,15 +1509,15 @@ void x86_cpu_change_kvm_default(const char *prop, const char *value)
|
||||||
static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
||||||
bool migratable_only);
|
bool migratable_only);
|
||||||
|
|
||||||
#ifdef CONFIG_KVM
|
|
||||||
|
|
||||||
static bool lmce_supported(void)
|
static bool lmce_supported(void)
|
||||||
{
|
{
|
||||||
uint64_t mce_cap;
|
uint64_t mce_cap = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KVM
|
||||||
if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) {
|
if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return !!(mce_cap & MCG_LMCE_P);
|
return !!(mce_cap & MCG_LMCE_P);
|
||||||
}
|
}
|
||||||
|
@ -1531,51 +1537,28 @@ static int cpu_x86_fill_model_id(char *str)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static X86CPUDefinition host_cpudef;
|
static Property max_x86_cpu_properties[] = {
|
||||||
|
|
||||||
static Property host_x86_cpu_properties[] = {
|
|
||||||
DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true),
|
DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true),
|
||||||
DEFINE_PROP_BOOL("host-cache-info", X86CPU, cache_info_passthrough, false),
|
DEFINE_PROP_BOOL("host-cache-info", X86CPU, cache_info_passthrough, false),
|
||||||
DEFINE_PROP_END_OF_LIST()
|
DEFINE_PROP_END_OF_LIST()
|
||||||
};
|
};
|
||||||
|
|
||||||
/* class_init for the "host" CPU model
|
static void max_x86_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
*
|
|
||||||
* This function may be called before KVM is initialized.
|
|
||||||
*/
|
|
||||||
static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
|
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
||||||
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
|
||||||
|
|
||||||
xcc->kvm_required = true;
|
xcc->ordering = 9;
|
||||||
|
|
||||||
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
|
|
||||||
x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
|
|
||||||
|
|
||||||
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
|
|
||||||
host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
|
|
||||||
host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
|
|
||||||
host_cpudef.stepping = eax & 0x0F;
|
|
||||||
|
|
||||||
cpu_x86_fill_model_id(host_cpudef.model_id);
|
|
||||||
|
|
||||||
xcc->cpu_def = &host_cpudef;
|
|
||||||
xcc->model_description =
|
xcc->model_description =
|
||||||
"KVM processor with all supported host features "
|
"Enables all features supported by the accelerator in the current host";
|
||||||
"(only available in KVM mode)";
|
|
||||||
|
|
||||||
/* level, xlevel, xlevel2, and the feature words are initialized on
|
dc->props = max_x86_cpu_properties;
|
||||||
* instance_init, because they require KVM to be initialized.
|
|
||||||
*/
|
|
||||||
|
|
||||||
dc->props = host_x86_cpu_properties;
|
|
||||||
/* Reason: host_x86_cpu_initfn() dies when !kvm_enabled() */
|
|
||||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void host_x86_cpu_initfn(Object *obj)
|
static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp);
|
||||||
|
|
||||||
|
static void max_x86_cpu_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
X86CPU *cpu = X86_CPU(obj);
|
X86CPU *cpu = X86_CPU(obj);
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
|
@ -1584,10 +1567,24 @@ static void host_x86_cpu_initfn(Object *obj)
|
||||||
/* We can't fill the features array here because we don't know yet if
|
/* We can't fill the features array here because we don't know yet if
|
||||||
* "migratable" is true or false.
|
* "migratable" is true or false.
|
||||||
*/
|
*/
|
||||||
cpu->host_features = true;
|
cpu->max_features = true;
|
||||||
|
|
||||||
/* If KVM is disabled, x86_cpu_realizefn() will report an error later */
|
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
|
X86CPUDefinition host_cpudef = { };
|
||||||
|
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||||
|
|
||||||
|
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
|
||||||
|
x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
|
||||||
|
|
||||||
|
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
|
||||||
|
host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
|
||||||
|
host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
|
||||||
|
host_cpudef.stepping = eax & 0x0F;
|
||||||
|
|
||||||
|
cpu_x86_fill_model_id(host_cpudef.model_id);
|
||||||
|
|
||||||
|
x86_cpu_load_def(cpu, &host_cpudef, &error_abort);
|
||||||
|
|
||||||
env->cpuid_min_level =
|
env->cpuid_min_level =
|
||||||
kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
|
kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
|
||||||
env->cpuid_min_xlevel =
|
env->cpuid_min_xlevel =
|
||||||
|
@ -1598,15 +1595,44 @@ static void host_x86_cpu_initfn(Object *obj)
|
||||||
if (lmce_supported()) {
|
if (lmce_supported()) {
|
||||||
object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort);
|
object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
object_property_set_str(OBJECT(cpu), CPUID_VENDOR_AMD,
|
||||||
|
"vendor", &error_abort);
|
||||||
|
object_property_set_int(OBJECT(cpu), 6, "family", &error_abort);
|
||||||
|
object_property_set_int(OBJECT(cpu), 6, "model", &error_abort);
|
||||||
|
object_property_set_int(OBJECT(cpu), 3, "stepping", &error_abort);
|
||||||
|
object_property_set_str(OBJECT(cpu),
|
||||||
|
"QEMU TCG CPU version " QEMU_HW_VERSION,
|
||||||
|
"model-id", &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
|
object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const TypeInfo max_x86_cpu_type_info = {
|
||||||
|
.name = X86_CPU_TYPE_NAME("max"),
|
||||||
|
.parent = TYPE_X86_CPU,
|
||||||
|
.instance_init = max_x86_cpu_initfn,
|
||||||
|
.class_init = max_x86_cpu_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_KVM
|
||||||
|
|
||||||
|
static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
||||||
|
|
||||||
|
xcc->kvm_required = true;
|
||||||
|
xcc->ordering = 8;
|
||||||
|
|
||||||
|
xcc->model_description =
|
||||||
|
"KVM processor with all supported host features "
|
||||||
|
"(only available in KVM mode)";
|
||||||
|
}
|
||||||
|
|
||||||
static const TypeInfo host_x86_cpu_type_info = {
|
static const TypeInfo host_x86_cpu_type_info = {
|
||||||
.name = X86_CPU_TYPE_NAME("host"),
|
.name = X86_CPU_TYPE_NAME("host"),
|
||||||
.parent = TYPE_X86_CPU,
|
.parent = X86_CPU_TYPE_NAME("max"),
|
||||||
.instance_init = host_x86_cpu_initfn,
|
|
||||||
.class_init = host_x86_cpu_class_init,
|
.class_init = host_x86_cpu_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2060,7 +2086,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x86_cpu_load_features(X86CPU *cpu, Error **errp);
|
static void x86_cpu_expand_features(X86CPU *cpu, Error **errp);
|
||||||
static int x86_cpu_filter_features(X86CPU *cpu);
|
static int x86_cpu_filter_features(X86CPU *cpu);
|
||||||
|
|
||||||
/* Check for missing features that may prevent the CPU class from
|
/* Check for missing features that may prevent the CPU class from
|
||||||
|
@ -2083,9 +2109,9 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc,
|
||||||
|
|
||||||
xc = X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(xcc))));
|
xc = X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(xcc))));
|
||||||
|
|
||||||
x86_cpu_load_features(xc, &err);
|
x86_cpu_expand_features(xc, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
/* Errors at x86_cpu_load_features should never happen,
|
/* Errors at x86_cpu_expand_features should never happen,
|
||||||
* but in case it does, just report the model as not
|
* but in case it does, just report the model as not
|
||||||
* runnable at all using the "type" property.
|
* runnable at all using the "type" property.
|
||||||
*/
|
*/
|
||||||
|
@ -2128,7 +2154,7 @@ static void listflags(FILE *f, fprintf_function print, const char **featureset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort alphabetically by type name, listing kvm_required models last. */
|
/* Sort alphabetically by type name, respecting X86CPUClass::ordering. */
|
||||||
static gint x86_cpu_list_compare(gconstpointer a, gconstpointer b)
|
static gint x86_cpu_list_compare(gconstpointer a, gconstpointer b)
|
||||||
{
|
{
|
||||||
ObjectClass *class_a = (ObjectClass *)a;
|
ObjectClass *class_a = (ObjectClass *)a;
|
||||||
|
@ -2137,9 +2163,8 @@ static gint x86_cpu_list_compare(gconstpointer a, gconstpointer b)
|
||||||
X86CPUClass *cc_b = X86_CPU_CLASS(class_b);
|
X86CPUClass *cc_b = X86_CPU_CLASS(class_b);
|
||||||
const char *name_a, *name_b;
|
const char *name_a, *name_b;
|
||||||
|
|
||||||
if (cc_a->kvm_required != cc_b->kvm_required) {
|
if (cc_a->ordering != cc_b->ordering) {
|
||||||
/* kvm_required items go last */
|
return cc_a->ordering - cc_b->ordering;
|
||||||
return cc_a->kvm_required ? 1 : -1;
|
|
||||||
} else {
|
} else {
|
||||||
name_a = object_class_get_name(class_a);
|
name_a = object_class_get_name(class_a);
|
||||||
name_b = object_class_get_name(class_b);
|
name_b = object_class_get_name(class_b);
|
||||||
|
@ -2161,7 +2186,7 @@ static void x86_cpu_list_entry(gpointer data, gpointer user_data)
|
||||||
CPUListState *s = user_data;
|
CPUListState *s = user_data;
|
||||||
char *name = x86_cpu_class_get_model_name(cc);
|
char *name = x86_cpu_class_get_model_name(cc);
|
||||||
const char *desc = cc->model_description;
|
const char *desc = cc->model_description;
|
||||||
if (!desc) {
|
if (!desc && cc->cpu_def) {
|
||||||
desc = cc->cpu_def->model_id;
|
desc = cc->cpu_def->model_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2210,6 +2235,7 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
|
||||||
info->q_typename = g_strdup(object_class_get_name(oc));
|
info->q_typename = g_strdup(object_class_get_name(oc));
|
||||||
info->migration_safe = cc->migration_safe;
|
info->migration_safe = cc->migration_safe;
|
||||||
info->has_migration_safe = true;
|
info->has_migration_safe = true;
|
||||||
|
info->q_static = cc->static_model;
|
||||||
|
|
||||||
entry = g_malloc0(sizeof(*entry));
|
entry = g_malloc0(sizeof(*entry));
|
||||||
entry->value = info;
|
entry->value = info;
|
||||||
|
@ -2247,31 +2273,6 @@ static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Filters CPU feature words based on host availability of each feature.
|
|
||||||
*
|
|
||||||
* Returns: 0 if all flags are supported by the host, non-zero otherwise.
|
|
||||||
*/
|
|
||||||
static int x86_cpu_filter_features(X86CPU *cpu)
|
|
||||||
{
|
|
||||||
CPUX86State *env = &cpu->env;
|
|
||||||
FeatureWord w;
|
|
||||||
int rv = 0;
|
|
||||||
|
|
||||||
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
||||||
uint32_t host_feat =
|
|
||||||
x86_cpu_get_supported_feature_word(w, false);
|
|
||||||
uint32_t requested_features = env->features[w];
|
|
||||||
env->features[w] &= host_feat;
|
|
||||||
cpu->filtered_features[w] = requested_features & ~env->features[w];
|
|
||||||
if (cpu->filtered_features[w]) {
|
|
||||||
rv = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void x86_cpu_report_filtered_features(X86CPU *cpu)
|
static void x86_cpu_report_filtered_features(X86CPU *cpu)
|
||||||
{
|
{
|
||||||
FeatureWord w;
|
FeatureWord w;
|
||||||
|
@ -2293,7 +2294,7 @@ static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load data from X86CPUDefinition
|
/* Load data from X86CPUDefinition into a X86CPU object
|
||||||
*/
|
*/
|
||||||
static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
|
static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -2302,6 +2303,11 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
|
||||||
char host_vendor[CPUID_VENDOR_SZ + 1];
|
char host_vendor[CPUID_VENDOR_SZ + 1];
|
||||||
FeatureWord w;
|
FeatureWord w;
|
||||||
|
|
||||||
|
/*NOTE: any property set by this function should be returned by
|
||||||
|
* x86_cpu_static_props(), so static expansion of
|
||||||
|
* query-cpu-model-expansion is always complete.
|
||||||
|
*/
|
||||||
|
|
||||||
/* CPU models only set _minimum_ values for level/xlevel: */
|
/* CPU models only set _minimum_ values for level/xlevel: */
|
||||||
object_property_set_int(OBJECT(cpu), def->level, "min-level", errp);
|
object_property_set_int(OBJECT(cpu), def->level, "min-level", errp);
|
||||||
object_property_set_int(OBJECT(cpu), def->xlevel, "min-xlevel", errp);
|
object_property_set_int(OBJECT(cpu), def->xlevel, "min-xlevel", errp);
|
||||||
|
@ -2346,6 +2352,212 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a QDict containing keys for all properties that can be included
|
||||||
|
* in static expansion of CPU models. All properties set by x86_cpu_load_def()
|
||||||
|
* must be included in the dictionary.
|
||||||
|
*/
|
||||||
|
static QDict *x86_cpu_static_props(void)
|
||||||
|
{
|
||||||
|
FeatureWord w;
|
||||||
|
int i;
|
||||||
|
static const char *props[] = {
|
||||||
|
"min-level",
|
||||||
|
"min-xlevel",
|
||||||
|
"family",
|
||||||
|
"model",
|
||||||
|
"stepping",
|
||||||
|
"model-id",
|
||||||
|
"vendor",
|
||||||
|
"lmce",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
static QDict *d;
|
||||||
|
|
||||||
|
if (d) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = qdict_new();
|
||||||
|
for (i = 0; props[i]; i++) {
|
||||||
|
qdict_put_obj(d, props[i], qnull());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||||
|
FeatureWordInfo *fi = &feature_word_info[w];
|
||||||
|
int bit;
|
||||||
|
for (bit = 0; bit < 32; bit++) {
|
||||||
|
if (!fi->feat_names[bit]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
qdict_put_obj(d, fi->feat_names[bit], qnull());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an entry to @props dict, with the value for property. */
|
||||||
|
static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop)
|
||||||
|
{
|
||||||
|
QObject *value = object_property_get_qobject(OBJECT(cpu), prop,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
|
qdict_put_obj(props, prop, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert CPU model data from X86CPU object to a property dictionary
|
||||||
|
* that can recreate exactly the same CPU model.
|
||||||
|
*/
|
||||||
|
static void x86_cpu_to_dict(X86CPU *cpu, QDict *props)
|
||||||
|
{
|
||||||
|
QDict *sprops = x86_cpu_static_props();
|
||||||
|
const QDictEntry *e;
|
||||||
|
|
||||||
|
for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) {
|
||||||
|
const char *prop = qdict_entry_key(e);
|
||||||
|
x86_cpu_expand_prop(cpu, props, prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert CPU model data from X86CPU object to a property dictionary
|
||||||
|
* that can recreate exactly the same CPU model, including every
|
||||||
|
* writeable QOM property.
|
||||||
|
*/
|
||||||
|
static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props)
|
||||||
|
{
|
||||||
|
ObjectPropertyIterator iter;
|
||||||
|
ObjectProperty *prop;
|
||||||
|
|
||||||
|
object_property_iter_init(&iter, OBJECT(cpu));
|
||||||
|
while ((prop = object_property_iter_next(&iter))) {
|
||||||
|
/* skip read-only or write-only properties */
|
||||||
|
if (!prop->get || !prop->set) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "hotplugged" is the only property that is configurable
|
||||||
|
* on the command-line but will be set differently on CPUs
|
||||||
|
* created using "-cpu ... -smp ..." and by CPUs created
|
||||||
|
* on the fly by x86_cpu_from_model() for querying. Skip it.
|
||||||
|
*/
|
||||||
|
if (!strcmp(prop->name, "hotplugged")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
x86_cpu_expand_prop(cpu, props, prop->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void object_apply_props(Object *obj, QDict *props, Error **errp)
|
||||||
|
{
|
||||||
|
const QDictEntry *prop;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) {
|
||||||
|
object_property_set_qobject(obj, qdict_entry_value(prop),
|
||||||
|
qdict_entry_key(prop), &err);
|
||||||
|
if (err) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error_propagate(errp, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create X86CPU object according to model+props specification */
|
||||||
|
static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp)
|
||||||
|
{
|
||||||
|
X86CPU *xc = NULL;
|
||||||
|
X86CPUClass *xcc;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model));
|
||||||
|
if (xcc == NULL) {
|
||||||
|
error_setg(&err, "CPU model '%s' not found", model);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
xc = X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(xcc))));
|
||||||
|
if (props) {
|
||||||
|
object_apply_props(OBJECT(xc), props, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_cpu_expand_features(xc, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
object_unref(OBJECT(xc));
|
||||||
|
xc = NULL;
|
||||||
|
}
|
||||||
|
return xc;
|
||||||
|
}
|
||||||
|
|
||||||
|
CpuModelExpansionInfo *
|
||||||
|
arch_query_cpu_model_expansion(CpuModelExpansionType type,
|
||||||
|
CpuModelInfo *model,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
X86CPU *xc = NULL;
|
||||||
|
Error *err = NULL;
|
||||||
|
CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1);
|
||||||
|
QDict *props = NULL;
|
||||||
|
const char *base_name;
|
||||||
|
|
||||||
|
xc = x86_cpu_from_model(model->name,
|
||||||
|
model->has_props ?
|
||||||
|
qobject_to_qdict(model->props) :
|
||||||
|
NULL, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
props = qdict_new();
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case CPU_MODEL_EXPANSION_TYPE_STATIC:
|
||||||
|
/* Static expansion will be based on "base" only */
|
||||||
|
base_name = "base";
|
||||||
|
x86_cpu_to_dict(xc, props);
|
||||||
|
break;
|
||||||
|
case CPU_MODEL_EXPANSION_TYPE_FULL:
|
||||||
|
/* As we don't return every single property, full expansion needs
|
||||||
|
* to keep the original model name+props, and add extra
|
||||||
|
* properties on top of that.
|
||||||
|
*/
|
||||||
|
base_name = model->name;
|
||||||
|
x86_cpu_to_dict_full(xc, props);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(&err, "Unsupportted expansion type");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props) {
|
||||||
|
props = qdict_new();
|
||||||
|
}
|
||||||
|
x86_cpu_to_dict(xc, props);
|
||||||
|
|
||||||
|
ret->model = g_new0(CpuModelInfo, 1);
|
||||||
|
ret->model->name = g_strdup(base_name);
|
||||||
|
ret->model->props = QOBJECT(props);
|
||||||
|
ret->model->has_props = true;
|
||||||
|
|
||||||
|
out:
|
||||||
|
object_unref(OBJECT(xc));
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
qapi_free_CpuModelExpansionInfo(ret);
|
||||||
|
ret = NULL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
X86CPU *cpu_x86_init(const char *cpu_model)
|
X86CPU *cpu_x86_init(const char *cpu_model)
|
||||||
{
|
{
|
||||||
return X86_CPU(cpu_generic_init(TYPE_X86_CPU, cpu_model));
|
return X86_CPU(cpu_generic_init(TYPE_X86_CPU, cpu_model));
|
||||||
|
@ -3095,20 +3307,59 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu)
|
||||||
env->features[FEAT_XSAVE_COMP_HI] = mask >> 32;
|
env->features[FEAT_XSAVE_COMP_HI] = mask >> 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load CPUID data based on configured features */
|
/***** Steps involved on loading and filtering CPUID data
|
||||||
static void x86_cpu_load_features(X86CPU *cpu, Error **errp)
|
*
|
||||||
|
* When initializing and realizing a CPU object, the steps
|
||||||
|
* involved in setting up CPUID data are:
|
||||||
|
*
|
||||||
|
* 1) Loading CPU model definition (X86CPUDefinition). This is
|
||||||
|
* implemented by x86_cpu_load_def() and should be completely
|
||||||
|
* transparent, as it is done automatically by instance_init.
|
||||||
|
* No code should need to look at X86CPUDefinition structs
|
||||||
|
* outside instance_init.
|
||||||
|
*
|
||||||
|
* 2) CPU expansion. This is done by realize before CPUID
|
||||||
|
* filtering, and will make sure host/accelerator data is
|
||||||
|
* loaded for CPU models that depend on host capabilities
|
||||||
|
* (e.g. "host"). Done by x86_cpu_expand_features().
|
||||||
|
*
|
||||||
|
* 3) CPUID filtering. This initializes extra data related to
|
||||||
|
* CPUID, and checks if the host supports all capabilities
|
||||||
|
* required by the CPU. Runnability of a CPU model is
|
||||||
|
* determined at this step. Done by x86_cpu_filter_features().
|
||||||
|
*
|
||||||
|
* Some operations don't require all steps to be performed.
|
||||||
|
* More precisely:
|
||||||
|
*
|
||||||
|
* - CPU instance creation (instance_init) will run only CPU
|
||||||
|
* model loading. CPU expansion can't run at instance_init-time
|
||||||
|
* because host/accelerator data may be not available yet.
|
||||||
|
* - CPU realization will perform both CPU model expansion and CPUID
|
||||||
|
* filtering, and return an error in case one of them fails.
|
||||||
|
* - query-cpu-definitions needs to run all 3 steps. It needs
|
||||||
|
* to run CPUID filtering, as the 'unavailable-features'
|
||||||
|
* field is set based on the filtering results.
|
||||||
|
* - The query-cpu-model-expansion QMP command only needs to run
|
||||||
|
* CPU model loading and CPU expansion. It should not filter
|
||||||
|
* any CPUID data based on host capabilities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Expand CPU configuration data, based on configured features
|
||||||
|
* and host/accelerator capabilities when appropriate.
|
||||||
|
*/
|
||||||
|
static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
||||||
{
|
{
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
FeatureWord w;
|
FeatureWord w;
|
||||||
GList *l;
|
GList *l;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
/*TODO: cpu->host_features incorrectly overwrites features
|
/*TODO: cpu->max_features incorrectly overwrites features
|
||||||
* set using "feat=on|off". Once we fix this, we can convert
|
* set using "feat=on|off". Once we fix this, we can convert
|
||||||
* plus_features & minus_features to global properties
|
* plus_features & minus_features to global properties
|
||||||
* inside x86_cpu_parse_featurestr() too.
|
* inside x86_cpu_parse_featurestr() too.
|
||||||
*/
|
*/
|
||||||
if (cpu->host_features) {
|
if (cpu->max_features) {
|
||||||
for (w = 0; w < FEATURE_WORDS; w++) {
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||||
env->features[w] =
|
env->features[w] =
|
||||||
x86_cpu_get_supported_feature_word(w, cpu->migratable);
|
x86_cpu_get_supported_feature_word(w, cpu->migratable);
|
||||||
|
@ -3173,6 +3424,32 @@ out:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finishes initialization of CPUID data, filters CPU feature
|
||||||
|
* words based on host availability of each feature.
|
||||||
|
*
|
||||||
|
* Returns: 0 if all flags are supported by the host, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
static int x86_cpu_filter_features(X86CPU *cpu)
|
||||||
|
{
|
||||||
|
CPUX86State *env = &cpu->env;
|
||||||
|
FeatureWord w;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||||
|
uint32_t host_feat =
|
||||||
|
x86_cpu_get_supported_feature_word(w, false);
|
||||||
|
uint32_t requested_features = env->features[w];
|
||||||
|
env->features[w] &= host_feat;
|
||||||
|
cpu->filtered_features[w] = requested_features & ~env->features[w];
|
||||||
|
if (cpu->filtered_features[w]) {
|
||||||
|
rv = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \
|
#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \
|
||||||
(env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \
|
(env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \
|
||||||
(env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3)
|
(env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3)
|
||||||
|
@ -3200,7 +3477,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
x86_cpu_load_features(cpu, &local_err);
|
x86_cpu_expand_features(cpu, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -3619,7 +3896,9 @@ static void x86_cpu_initfn(Object *obj)
|
||||||
object_property_add_alias(obj, "sse4_1", obj, "sse4.1", &error_abort);
|
object_property_add_alias(obj, "sse4_1", obj, "sse4.1", &error_abort);
|
||||||
object_property_add_alias(obj, "sse4_2", obj, "sse4.2", &error_abort);
|
object_property_add_alias(obj, "sse4_2", obj, "sse4.2", &error_abort);
|
||||||
|
|
||||||
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
|
if (xcc->cpu_def) {
|
||||||
|
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t x86_cpu_get_arch_id(CPUState *cs)
|
static int64_t x86_cpu_get_arch_id(CPUState *cs)
|
||||||
|
@ -3774,6 +4053,24 @@ static const TypeInfo x86_cpu_type_info = {
|
||||||
.class_init = x86_cpu_common_class_init,
|
.class_init = x86_cpu_common_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* "base" CPU model, used by query-cpu-model-expansion */
|
||||||
|
static void x86_cpu_base_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
||||||
|
|
||||||
|
xcc->static_model = true;
|
||||||
|
xcc->migration_safe = true;
|
||||||
|
xcc->model_description = "base CPU model type with no features enabled";
|
||||||
|
xcc->ordering = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo x86_base_cpu_type_info = {
|
||||||
|
.name = X86_CPU_TYPE_NAME("base"),
|
||||||
|
.parent = TYPE_X86_CPU,
|
||||||
|
.class_init = x86_cpu_base_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void x86_cpu_register_types(void)
|
static void x86_cpu_register_types(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -3782,6 +4079,8 @@ static void x86_cpu_register_types(void)
|
||||||
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
||||||
x86_register_cpudef_type(&builtin_x86_defs[i]);
|
x86_register_cpudef_type(&builtin_x86_defs[i]);
|
||||||
}
|
}
|
||||||
|
type_register_static(&max_x86_cpu_type_info);
|
||||||
|
type_register_static(&x86_base_cpu_type_info);
|
||||||
#ifdef CONFIG_KVM
|
#ifdef CONFIG_KVM
|
||||||
type_register_static(&host_x86_cpu_type_info);
|
type_register_static(&host_x86_cpu_type_info);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1211,7 +1211,7 @@ struct X86CPU {
|
||||||
bool enforce_cpuid;
|
bool enforce_cpuid;
|
||||||
bool expose_kvm;
|
bool expose_kvm;
|
||||||
bool migratable;
|
bool migratable;
|
||||||
bool host_features;
|
bool max_features; /* Enable all supported features automatically */
|
||||||
uint32_t apic_id;
|
uint32_t apic_id;
|
||||||
|
|
||||||
/* Enables publishing of TSC increment and Local APIC bus frequencies to
|
/* Enables publishing of TSC increment and Local APIC bus frequencies to
|
||||||
|
|
Loading…
Reference in New Issue