|
@@ -789,7 +789,7 @@ typedef struct FeatureWordInfo {
|
|
|
* In cases of disagreement between feature naming conventions,
|
|
|
* aliases may be added.
|
|
|
*/
|
|
|
- const char *feat_names[32];
|
|
|
+ const char *feat_names[64];
|
|
|
union {
|
|
|
/* If type==CPUID_FEATURE_WORD */
|
|
|
struct {
|
|
@@ -801,17 +801,13 @@ typedef struct FeatureWordInfo {
|
|
|
/* If type==MSR_FEATURE_WORD */
|
|
|
struct {
|
|
|
uint32_t index;
|
|
|
- struct { /*CPUID that enumerate this MSR*/
|
|
|
- FeatureWord cpuid_class;
|
|
|
- uint32_t cpuid_flag;
|
|
|
- } cpuid_dep;
|
|
|
} msr;
|
|
|
};
|
|
|
- uint32_t tcg_features; /* Feature flags supported by TCG */
|
|
|
- uint32_t unmigratable_flags; /* Feature flags known to be unmigratable */
|
|
|
- uint32_t migratable_flags; /* Feature flags known to be migratable */
|
|
|
+ uint64_t tcg_features; /* Feature flags supported by TCG */
|
|
|
+ uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */
|
|
|
+ uint64_t migratable_flags; /* Feature flags known to be migratable */
|
|
|
/* Features that shouldn't be auto-enabled by "-cpu host" */
|
|
|
- uint32_t no_autoenable_flags;
|
|
|
+ uint64_t no_autoenable_flags;
|
|
|
} FeatureWordInfo;
|
|
|
|
|
|
static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|
@@ -1134,7 +1130,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|
|
[FEAT_8000_0008_EBX] = {
|
|
|
.type = CPUID_FEATURE_WORD,
|
|
|
.feat_names = {
|
|
|
- NULL, NULL, NULL, NULL,
|
|
|
+ "clzero", NULL, "xsaveerptr", NULL,
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
NULL, "wbnoinvd", NULL, NULL,
|
|
|
"ibpb", NULL, NULL, NULL,
|
|
@@ -1218,10 +1214,6 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|
|
},
|
|
|
.msr = {
|
|
|
.index = MSR_IA32_ARCH_CAPABILITIES,
|
|
|
- .cpuid_dep = {
|
|
|
- FEAT_7_0_EDX,
|
|
|
- CPUID_7_0_EDX_ARCH_CAPABILITIES
|
|
|
- }
|
|
|
},
|
|
|
},
|
|
|
[FEAT_CORE_CAPABILITY] = {
|
|
@@ -1238,12 +1230,253 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|
|
},
|
|
|
.msr = {
|
|
|
.index = MSR_IA32_CORE_CAPABILITY,
|
|
|
- .cpuid_dep = {
|
|
|
- FEAT_7_0_EDX,
|
|
|
- CPUID_7_0_EDX_CORE_CAPABILITY,
|
|
|
- },
|
|
|
},
|
|
|
},
|
|
|
+
|
|
|
+ [FEAT_VMX_PROCBASED_CTLS] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ NULL, NULL, "vmx-vintr-pending", "vmx-tsc-offset",
|
|
|
+ NULL, NULL, NULL, "vmx-hlt-exit",
|
|
|
+ NULL, "vmx-invlpg-exit", "vmx-mwait-exit", "vmx-rdpmc-exit",
|
|
|
+ "vmx-rdtsc-exit", NULL, NULL, "vmx-cr3-load-noexit",
|
|
|
+ "vmx-cr3-store-noexit", NULL, NULL, "vmx-cr8-load-exit",
|
|
|
+ "vmx-cr8-store-exit", "vmx-flexpriority", "vmx-vnmi-pending", "vmx-movdr-exit",
|
|
|
+ "vmx-io-exit", "vmx-io-bitmap", NULL, "vmx-mtf",
|
|
|
+ "vmx-msr-bitmap", "vmx-monitor-exit", "vmx-pause-exit", "vmx-secondary-ctls",
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_SECONDARY_CTLS] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ "vmx-apicv-xapic", "vmx-ept", "vmx-desc-exit", "vmx-rdtscp-exit",
|
|
|
+ "vmx-apicv-x2apic", "vmx-vpid", "vmx-wbinvd-exit", "vmx-unrestricted-guest",
|
|
|
+ "vmx-apicv-register", "vmx-apicv-vid", "vmx-ple", "vmx-rdrand-exit",
|
|
|
+ "vmx-invpcid-exit", "vmx-vmfunc", "vmx-shadow-vmcs", "vmx-encls-exit",
|
|
|
+ "vmx-rdseed-exit", "vmx-pml", NULL, NULL,
|
|
|
+ "vmx-xsaves", NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_PROCBASED_CTLS2,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_PINBASED_CTLS] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ "vmx-intr-exit", NULL, NULL, "vmx-nmi-exit",
|
|
|
+ NULL, "vmx-vnmi", "vmx-preemption-timer", "vmx-posted-intr",
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_TRUE_PINBASED_CTLS,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_EXIT_CTLS] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ /*
|
|
|
+ * VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE is copied from
|
|
|
+ * the LM CPUID bit.
|
|
|
+ */
|
|
|
+ .feat_names = {
|
|
|
+ NULL, NULL, "vmx-exit-nosave-debugctl", NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL /* vmx-exit-host-addr-space-size */, NULL, NULL,
|
|
|
+ "vmx-exit-load-perf-global-ctrl", NULL, NULL, "vmx-exit-ack-intr",
|
|
|
+ NULL, NULL, "vmx-exit-save-pat", "vmx-exit-load-pat",
|
|
|
+ "vmx-exit-save-efer", "vmx-exit-load-efer",
|
|
|
+ "vmx-exit-save-preemption-timer", "vmx-exit-clear-bndcfgs",
|
|
|
+ NULL, "vmx-exit-clear-rtit-ctl", NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_TRUE_EXIT_CTLS,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_ENTRY_CTLS] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ NULL, NULL, "vmx-entry-noload-debugctl", NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, "vmx-entry-ia32e-mode", NULL, NULL,
|
|
|
+ NULL, "vmx-entry-load-perf-global-ctrl", "vmx-entry-load-pat", "vmx-entry-load-efer",
|
|
|
+ "vmx-entry-load-bndcfgs", NULL, "vmx-entry-load-rtit-ctl", NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_TRUE_ENTRY_CTLS,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_MISC] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, "vmx-store-lma", "vmx-activity-hlt", "vmx-activity-shutdown",
|
|
|
+ "vmx-activity-wait-sipi", NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, "vmx-vmwrite-vmexit-fields", "vmx-zero-len-inject", NULL,
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_MISC,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_EPT_VPID_CAPS] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ "vmx-ept-execonly", NULL, NULL, NULL,
|
|
|
+ NULL, NULL, "vmx-page-walk-4", "vmx-page-walk-5",
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ "vmx-ept-2mb", "vmx-ept-1gb", NULL, NULL,
|
|
|
+ "vmx-invept", "vmx-eptad", "vmx-ept-advanced-exitinfo", NULL,
|
|
|
+ NULL, "vmx-invept-single-context", "vmx-invept-all-context", NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ "vmx-invvpid", NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ "vmx-invvpid-single-addr", "vmx-invept-single-context",
|
|
|
+ "vmx-invvpid-all-context", "vmx-invept-single-context-noglobals",
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ NULL, NULL, NULL, NULL,
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_EPT_VPID_CAP,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_BASIC] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ [54] = "vmx-ins-outs",
|
|
|
+ [55] = "vmx-true-ctls",
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_BASIC,
|
|
|
+ },
|
|
|
+ /* Just to be safe - we don't support setting the MSEG version field. */
|
|
|
+ .no_autoenable_flags = MSR_VMX_BASIC_DUAL_MONITOR,
|
|
|
+ },
|
|
|
+
|
|
|
+ [FEAT_VMX_VMFUNC] = {
|
|
|
+ .type = MSR_FEATURE_WORD,
|
|
|
+ .feat_names = {
|
|
|
+ [0] = "vmx-eptp-switching",
|
|
|
+ },
|
|
|
+ .msr = {
|
|
|
+ .index = MSR_IA32_VMX_VMFUNC,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+typedef struct FeatureMask {
|
|
|
+ FeatureWord index;
|
|
|
+ uint64_t mask;
|
|
|
+} FeatureMask;
|
|
|
+
|
|
|
+typedef struct FeatureDep {
|
|
|
+ FeatureMask from, to;
|
|
|
+} FeatureDep;
|
|
|
+
|
|
|
+static FeatureDep feature_dependencies[] = {
|
|
|
+ {
|
|
|
+ .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_ARCH_CAPABILITIES },
|
|
|
+ .to = { FEAT_ARCH_CAPABILITIES, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY },
|
|
|
+ .to = { FEAT_CORE_CAPABILITY, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
|
|
|
+ .to = { FEAT_VMX_PROCBASED_CTLS, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
|
|
|
+ .to = { FEAT_VMX_PINBASED_CTLS, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
|
|
|
+ .to = { FEAT_VMX_EXIT_CTLS, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
|
|
|
+ .to = { FEAT_VMX_ENTRY_CTLS, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
|
|
|
+ .to = { FEAT_VMX_MISC, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
|
|
|
+ .to = { FEAT_VMX_BASIC, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_8000_0001_EDX, CPUID_EXT2_LM },
|
|
|
+ .to = { FEAT_VMX_ENTRY_CTLS, VMX_VM_ENTRY_IA32E_MODE },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_VMX_PROCBASED_CTLS, VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS },
|
|
|
+ .to = { FEAT_VMX_SECONDARY_CTLS, ~0ull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_XSAVE, CPUID_XSAVE_XSAVES },
|
|
|
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_XSAVES },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_1_ECX, CPUID_EXT_RDRAND },
|
|
|
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDRAND_EXITING },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_INVPCID },
|
|
|
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_INVPCID },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_RDSEED },
|
|
|
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDSEED_EXITING },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_8000_0001_EDX, CPUID_EXT2_RDTSCP },
|
|
|
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDTSCP },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT },
|
|
|
+ .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT },
|
|
|
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VPID },
|
|
|
+ .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull << 32 },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VMFUNC },
|
|
|
+ .to = { FEAT_VMX_VMFUNC, ~0ull },
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
typedef struct X86RegisterInfo32 {
|
|
@@ -1354,14 +1587,14 @@ const char *get_register_name_32(unsigned int reg)
|
|
|
* Returns the set of feature flags that are supported and migratable by
|
|
|
* QEMU, for a given FeatureWord.
|
|
|
*/
|
|
|
-static uint32_t x86_cpu_get_migratable_flags(FeatureWord w)
|
|
|
+static uint64_t x86_cpu_get_migratable_flags(FeatureWord w)
|
|
|
{
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
|
|
- uint32_t r = 0;
|
|
|
+ uint64_t r = 0;
|
|
|
int i;
|
|
|
|
|
|
- for (i = 0; i < 32; i++) {
|
|
|
- uint32_t f = 1U << i;
|
|
|
+ for (i = 0; i < 64; i++) {
|
|
|
+ uint64_t f = 1ULL << i;
|
|
|
|
|
|
/* If the feature name is known, it is implicitly considered migratable,
|
|
|
* unless it is explicitly set in unmigratable_flags */
|
|
@@ -2923,7 +3156,7 @@ void x86_cpu_change_kvm_default(const char *prop, const char *value)
|
|
|
assert(pv->prop);
|
|
|
}
|
|
|
|
|
|
-static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
+static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
bool migratable_only);
|
|
|
|
|
|
static bool lmce_supported(void)
|
|
@@ -3096,17 +3329,41 @@ static char *feature_word_description(FeatureWordInfo *f, uint32_t bit)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static void report_unavailable_features(FeatureWord w, uint32_t mask)
|
|
|
+static bool x86_cpu_have_filtered_features(X86CPU *cpu)
|
|
|
{
|
|
|
+ FeatureWord w;
|
|
|
+
|
|
|
+ for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
+ if (cpu->filtered_features[w]) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
|
|
|
+ const char *verbose_prefix)
|
|
|
+{
|
|
|
+ CPUX86State *env = &cpu->env;
|
|
|
FeatureWordInfo *f = &feature_word_info[w];
|
|
|
int i;
|
|
|
char *feat_word_str;
|
|
|
|
|
|
- for (i = 0; i < 32; ++i) {
|
|
|
- if ((1UL << i) & mask) {
|
|
|
+ if (!cpu->force_features) {
|
|
|
+ env->features[w] &= ~mask;
|
|
|
+ }
|
|
|
+ cpu->filtered_features[w] |= mask;
|
|
|
+
|
|
|
+ if (!verbose_prefix) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < 64; ++i) {
|
|
|
+ if ((1ULL << i) & mask) {
|
|
|
feat_word_str = feature_word_description(f, i);
|
|
|
- warn_report("%s doesn't support requested feature: %s%s%s [bit %d]",
|
|
|
- accel_uses_host_cpuid() ? "host" : "TCG",
|
|
|
+ warn_report("%s: %s%s%s [bit %d]",
|
|
|
+ verbose_prefix,
|
|
|
feat_word_str,
|
|
|
f->feat_names[i] ? "." : "",
|
|
|
f->feat_names[i] ? f->feat_names[i] : "", i);
|
|
@@ -3346,7 +3603,7 @@ static void x86_cpu_get_feature_words(Object *obj, Visitor *v,
|
|
|
const char *name, void *opaque,
|
|
|
Error **errp)
|
|
|
{
|
|
|
- uint32_t *array = (uint32_t *)opaque;
|
|
|
+ uint64_t *array = (uint64_t *)opaque;
|
|
|
FeatureWord w;
|
|
|
X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
|
|
|
X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { };
|
|
@@ -3390,6 +3647,7 @@ static inline void feat2prop(char *s)
|
|
|
/* Return the feature property name for a feature flag bit */
|
|
|
static const char *x86_cpu_feature_name(FeatureWord w, int bitnr)
|
|
|
{
|
|
|
+ const char *name;
|
|
|
/* XSAVE components are automatically enabled by other features,
|
|
|
* so return the original feature name instead
|
|
|
*/
|
|
@@ -3403,9 +3661,11 @@ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- assert(bitnr < 32);
|
|
|
+ assert(bitnr < 64);
|
|
|
assert(w < FEATURE_WORDS);
|
|
|
- return feature_word_info[w].feat_names[bitnr];
|
|
|
+ name = feature_word_info[w].feat_names[bitnr];
|
|
|
+ assert(bitnr < 32 || !(name && feature_word_info[w].type == CPUID_FEATURE_WORD));
|
|
|
+ return name;
|
|
|
}
|
|
|
|
|
|
/* Compatibily hack to maintain legacy +-feat semantic,
|
|
@@ -3511,7 +3771,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
|
|
|
}
|
|
|
|
|
|
static void x86_cpu_expand_features(X86CPU *cpu, Error **errp);
|
|
|
-static int x86_cpu_filter_features(X86CPU *cpu);
|
|
|
+static void x86_cpu_filter_features(X86CPU *cpu, bool verbose);
|
|
|
|
|
|
/* Build a list with the name of all features on a feature word array */
|
|
|
static void x86_cpu_list_feature_names(FeatureWordArray features,
|
|
@@ -3521,10 +3781,10 @@ static void x86_cpu_list_feature_names(FeatureWordArray features,
|
|
|
strList **next = feat_names;
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
- uint32_t filtered = features[w];
|
|
|
+ uint64_t filtered = features[w];
|
|
|
int i;
|
|
|
- for (i = 0; i < 32; i++) {
|
|
|
- if (filtered & (1UL << i)) {
|
|
|
+ for (i = 0; i < 64; i++) {
|
|
|
+ if (filtered & (1ULL << i)) {
|
|
|
strList *new = g_new0(strList, 1);
|
|
|
new->value = g_strdup(x86_cpu_feature_name(w, i));
|
|
|
*next = new;
|
|
@@ -3576,7 +3836,7 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc,
|
|
|
next = &new->next;
|
|
|
}
|
|
|
|
|
|
- x86_cpu_filter_features(xc);
|
|
|
+ x86_cpu_filter_features(xc, false);
|
|
|
|
|
|
x86_cpu_list_feature_names(xc->filtered_features, next);
|
|
|
|
|
@@ -3693,7 +3953,7 @@ void x86_cpu_list(void)
|
|
|
names = NULL;
|
|
|
for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) {
|
|
|
FeatureWordInfo *fw = &feature_word_info[i];
|
|
|
- for (j = 0; j < 32; j++) {
|
|
|
+ for (j = 0; j < 64; j++) {
|
|
|
if (fw->feat_names[j]) {
|
|
|
names = g_list_append(names, (gpointer)fw->feat_names[j]);
|
|
|
}
|
|
@@ -3748,11 +4008,11 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
|
|
|
return cpu_list;
|
|
|
}
|
|
|
|
|
|
-static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
+static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
bool migratable_only)
|
|
|
{
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
|
|
- uint32_t r = 0;
|
|
|
+ uint64_t r = 0;
|
|
|
|
|
|
if (kvm_enabled()) {
|
|
|
switch (wi->type) {
|
|
@@ -3784,15 +4044,6 @@ static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
-static void x86_cpu_report_filtered_features(X86CPU *cpu)
|
|
|
-{
|
|
|
- FeatureWord w;
|
|
|
-
|
|
|
- for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
- report_unavailable_features(w, cpu->filtered_features[w]);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props)
|
|
|
{
|
|
|
PropValue *pv;
|
|
@@ -3932,7 +4183,7 @@ static QDict *x86_cpu_static_props(void)
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
FeatureWordInfo *fi = &feature_word_info[w];
|
|
|
int bit;
|
|
|
- for (bit = 0; bit < 32; bit++) {
|
|
|
+ for (bit = 0; bit < 64; bit++) {
|
|
|
if (!fi->feat_names[bit]) {
|
|
|
continue;
|
|
|
}
|
|
@@ -5048,9 +5299,26 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
|
|
{
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
FeatureWord w;
|
|
|
+ int i;
|
|
|
GList *l;
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
+ for (l = plus_features; l; l = l->next) {
|
|
|
+ const char *prop = l->data;
|
|
|
+ object_property_set_bool(OBJECT(cpu), true, prop, &local_err);
|
|
|
+ if (local_err) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (l = minus_features; l; l = l->next) {
|
|
|
+ const char *prop = l->data;
|
|
|
+ object_property_set_bool(OBJECT(cpu), false, prop, &local_err);
|
|
|
+ if (local_err) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*TODO: Now cpu->max_features doesn't overwrite features
|
|
|
* set using QOM properties, and we can convert
|
|
|
* plus_features & minus_features to global properties
|
|
@@ -5068,19 +5336,18 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- for (l = plus_features; l; l = l->next) {
|
|
|
- const char *prop = l->data;
|
|
|
- object_property_set_bool(OBJECT(cpu), true, prop, &local_err);
|
|
|
- if (local_err) {
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
+ for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) {
|
|
|
+ FeatureDep *d = &feature_dependencies[i];
|
|
|
+ if (!(env->features[d->from.index] & d->from.mask)) {
|
|
|
+ uint64_t unavailable_features = env->features[d->to.index] & d->to.mask;
|
|
|
|
|
|
- for (l = minus_features; l; l = l->next) {
|
|
|
- const char *prop = l->data;
|
|
|
- object_property_set_bool(OBJECT(cpu), false, prop, &local_err);
|
|
|
- if (local_err) {
|
|
|
- goto out;
|
|
|
+ /* Not an error unless the dependent feature was added explicitly. */
|
|
|
+ mark_unavailable_features(cpu, d->to.index,
|
|
|
+ unavailable_features & env->user_features[d->to.index],
|
|
|
+ "This feature depends on other features that were not requested");
|
|
|
+
|
|
|
+ env->user_features[d->to.index] |= unavailable_features;
|
|
|
+ env->features[d->to.index] &= ~unavailable_features;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -5154,24 +5421,24 @@ out:
|
|
|
*
|
|
|
* Returns: 0 if all flags are supported by the host, non-zero otherwise.
|
|
|
*/
|
|
|
-static int x86_cpu_filter_features(X86CPU *cpu)
|
|
|
+static void x86_cpu_filter_features(X86CPU *cpu, bool verbose)
|
|
|
{
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
FeatureWord w;
|
|
|
- int rv = 0;
|
|
|
+ const char *prefix = NULL;
|
|
|
+
|
|
|
+ if (verbose) {
|
|
|
+ prefix = accel_uses_host_cpuid()
|
|
|
+ ? "host doesn't support requested feature"
|
|
|
+ : "TCG doesn't support requested feature";
|
|
|
+ }
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
- uint32_t host_feat =
|
|
|
+ uint64_t host_feat =
|
|
|
x86_cpu_get_supported_feature_word(w, false);
|
|
|
- uint32_t requested_features = env->features[w];
|
|
|
- uint32_t available_features = requested_features & host_feat;
|
|
|
- if (!cpu->force_features) {
|
|
|
- env->features[w] = available_features;
|
|
|
- }
|
|
|
- cpu->filtered_features[w] = requested_features & ~available_features;
|
|
|
- if (cpu->filtered_features[w]) {
|
|
|
- rv = 1;
|
|
|
- }
|
|
|
+ uint64_t requested_features = env->features[w];
|
|
|
+ uint64_t unavailable_features = requested_features & ~host_feat;
|
|
|
+ mark_unavailable_features(cpu, w, unavailable_features, prefix);
|
|
|
}
|
|
|
|
|
|
if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) &&
|
|
@@ -5197,13 +5464,9 @@ static int x86_cpu_filter_features(X86CPU *cpu)
|
|
|
* host can't emulate the capabilities we report on
|
|
|
* cpu_x86_cpuid(), intel-pt can't be enabled on the current host.
|
|
|
*/
|
|
|
- env->features[FEAT_7_0_EBX] &= ~CPUID_7_0_EBX_INTEL_PT;
|
|
|
- cpu->filtered_features[FEAT_7_0_EBX] |= CPUID_7_0_EBX_INTEL_PT;
|
|
|
- rv = 1;
|
|
|
+ mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, prefix);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return rv;
|
|
|
}
|
|
|
|
|
|
static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
|
@@ -5244,16 +5507,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (x86_cpu_filter_features(cpu) &&
|
|
|
- (cpu->check_cpuid || cpu->enforce_cpuid)) {
|
|
|
- x86_cpu_report_filtered_features(cpu);
|
|
|
- if (cpu->enforce_cpuid) {
|
|
|
- error_setg(&local_err,
|
|
|
- accel_uses_host_cpuid() ?
|
|
|
- "Host doesn't support requested features" :
|
|
|
- "TCG doesn't support requested features");
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid);
|
|
|
+
|
|
|
+ if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) {
|
|
|
+ error_setg(&local_err,
|
|
|
+ accel_uses_host_cpuid() ?
|
|
|
+ "Host doesn't support requested features" :
|
|
|
+ "TCG doesn't support requested features");
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
/* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
|
|
@@ -5473,7 +5734,7 @@ static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp)
|
|
|
|
|
|
typedef struct BitProperty {
|
|
|
FeatureWord w;
|
|
|
- uint32_t mask;
|
|
|
+ uint64_t mask;
|
|
|
} BitProperty;
|
|
|
|
|
|
static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name,
|
|
@@ -5481,7 +5742,7 @@ static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name,
|
|
|
{
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
BitProperty *fp = opaque;
|
|
|
- uint32_t f = cpu->env.features[fp->w];
|
|
|
+ uint64_t f = cpu->env.features[fp->w];
|
|
|
bool value = (f & fp->mask) == fp->mask;
|
|
|
visit_type_bool(v, name, &value, errp);
|
|
|
}
|
|
@@ -5534,7 +5795,7 @@ static void x86_cpu_register_bit_prop(X86CPU *cpu,
|
|
|
{
|
|
|
BitProperty *fp;
|
|
|
ObjectProperty *op;
|
|
|
- uint32_t mask = (1UL << bitnr);
|
|
|
+ uint64_t mask = (1ULL << bitnr);
|
|
|
|
|
|
op = object_property_find(OBJECT(cpu), prop_name, NULL);
|
|
|
if (op) {
|
|
@@ -5668,7 +5929,7 @@ static void x86_cpu_initfn(Object *obj)
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
int bitnr;
|
|
|
|
|
|
- for (bitnr = 0; bitnr < 32; bitnr++) {
|
|
|
+ for (bitnr = 0; bitnr < 64; bitnr++) {
|
|
|
x86_cpu_register_feature_bit_props(cpu, w, bitnr);
|
|
|
}
|
|
|
}
|
|
@@ -5984,7 +6245,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
cc->asidx_from_attrs = x86_asidx_from_attrs;
|
|
|
cc->get_memory_mapping = x86_cpu_get_memory_mapping;
|
|
|
- cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
|
|
|
+ cc->get_phys_page_attrs_debug = x86_cpu_get_phys_page_attrs_debug;
|
|
|
cc->write_elf64_note = x86_cpu_write_elf64_note;
|
|
|
cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote;
|
|
|
cc->write_elf32_note = x86_cpu_write_elf32_note;
|