* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
#include "cpu.h"
+#include "exec/exec-all.h"
#include "sysemu/kvm.h"
#include "sysemu/cpus.h"
#include "kvm_i386.h"
#include "qapi/visitor.h"
#include "sysemu/arch_init.h"
-#include "hw/hw.h"
#if defined(CONFIG_KVM)
#include <linux/kvm_para.h>
#endif
#include "sysemu/sysemu.h"
#include "hw/qdev-properties.h"
+#include "hw/i386/topology.h"
#ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h"
+#include "hw/hw.h"
#include "hw/xen/xen.h"
#include "hw/i386/apic_internal.h"
#endif
CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
CPUID_7_0_EBX_RDSEED */
-#define TCG_7_0_ECX_FEATURES 0
+#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE)
#define TCG_APM_FEATURES 0
#define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT
#define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1)
const ExtSaveArea x86_ext_save_areas[] = {
[XSTATE_YMM_BIT] =
{ .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
- .offset = 0x240, .size = 0x100 },
+ .offset = offsetof(X86XSaveArea, avx_state),
+ .size = sizeof(XSaveAVX) },
[XSTATE_BNDREGS_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
- .offset = 0x3c0, .size = 0x40 },
+ .offset = offsetof(X86XSaveArea, bndreg_state),
+ .size = sizeof(XSaveBNDREG) },
[XSTATE_BNDCSR_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
- .offset = 0x400, .size = 0x40 },
+ .offset = offsetof(X86XSaveArea, bndcsr_state),
+ .size = sizeof(XSaveBNDCSR) },
[XSTATE_OPMASK_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
- .offset = 0x440, .size = 0x40 },
+ .offset = offsetof(X86XSaveArea, opmask_state),
+ .size = sizeof(XSaveOpmask) },
[XSTATE_ZMM_Hi256_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
- .offset = 0x480, .size = 0x200 },
+ .offset = offsetof(X86XSaveArea, zmm_hi256_state),
+ .size = sizeof(XSaveZMM_Hi256) },
[XSTATE_Hi16_ZMM_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
- .offset = 0x680, .size = 0x400 },
+ .offset = offsetof(X86XSaveArea, hi16_zmm_state),
+ .size = sizeof(XSaveHi16_ZMM) },
[XSTATE_PKRU_BIT] =
{ .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU,
- .offset = 0xA80, .size = 0x8 },
+ .offset = offsetof(X86XSaveArea, pkru_state),
+ .size = sizeof(XSavePKRU) },
};
const char *get_register_name_32(unsigned int reg)
return oc;
}
+static char *x86_cpu_class_get_model_name(X86CPUClass *cc)
+{
+ const char *class_name = object_class_get_name(OBJECT_CLASS(cc));
+ assert(g_str_has_suffix(class_name, X86_CPU_TYPE_SUFFIX));
+ return g_strndup(class_name,
+ strlen(class_name) - strlen(X86_CPU_TYPE_SUFFIX));
+}
+
struct X86CPUDefinition {
const char *name;
uint32_t level;
.features[FEAT_8000_0001_ECX] =
CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM,
.xlevel = 0x8000000A,
+ .model_id = "QEMU Virtual CPU version " QEMU_HW_VERSION,
},
{
.name = "phenom",
.features[FEAT_1_ECX] =
CPUID_EXT_SSE3,
.xlevel = 0x80000004,
+ .model_id = "QEMU Virtual CPU version " QEMU_HW_VERSION,
},
{
.name = "kvm32",
.features[FEAT_8000_0001_EDX] =
CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
.xlevel = 0x80000008,
+ .model_id = "QEMU Virtual CPU version " QEMU_HW_VERSION,
},
{
.name = "n270",
.xlevel = 0x80000008,
.model_id = "Intel Core Processor (Broadwell)",
},
+ {
+ .name = "Skylake-Client",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 94,
+ .stepping = 3,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX,
+ /* Missing: XSAVES (not supported by some Linux versions,
+ * including v4.1 to v4.6).
+ * KVM doesn't yet expose any XSAVES state save component,
+ * and the only one defined in Skylake (processor tracing)
+ * probably will block migration anyway.
+ */
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Core Processor (Skylake)",
+ },
{
.name = "Opteron_G1",
.level = 5,
CPUX86State *env = &cpu->env;
KVMState *s = kvm_state;
- assert(kvm_enabled());
-
/* We can't fill the features array here because we don't know yet if
* "migratable" is true or false.
*/
cpu->host_features = true;
- env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
- env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
- env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+ /* If KVM is disabled, x86_cpu_realizefn() will report an error later */
+ if (kvm_enabled()) {
+ env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+ env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
+ env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+ }
object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
}
{
uint32_t *array = (uint32_t *)opaque;
FeatureWord w;
- Error *err = NULL;
X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { };
X86CPUFeatureWordInfoList *list = NULL;
list = &list_entries[w];
}
- visit_type_X86CPUFeatureWordInfoList(v, "feature-words", &list, &err);
- error_propagate(errp, err);
+ visit_type_X86CPUFeatureWordInfoList(v, "feature-words", &list, errp);
}
static void x86_get_hv_spinlocks(Object *obj, Visitor *v, const char *name,
}
}
+/* Compatibily hack to maintain legacy +-feat semantic,
+ * where +-feat overwrites any feature set by
+ * feat=on|feat even if the later is parsed after +-feat
+ * (i.e. "-x2apic,x2apic=on" will result in x2apic disabled)
+ */
+static FeatureWordArray plus_features = { 0 };
+static FeatureWordArray minus_features = { 0 };
+
/* Parse "+feature,-feature,feature=foo" CPU feature string
*/
static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
{
X86CPU *cpu = X86_CPU(cs);
char *featurestr; /* Single 'key=value" string being parsed */
- FeatureWord w;
- /* Features to be added */
- FeatureWordArray plus_features = { 0 };
- /* Features to be removed */
- FeatureWordArray minus_features = { 0 };
- uint32_t numvalue;
- CPUX86State *env = &cpu->env;
Error *local_err = NULL;
- featurestr = features ? strtok(features, ",") : NULL;
+ if (!features) {
+ return;
+ }
+
+ for (featurestr = strtok(features, ",");
+ featurestr && !local_err;
+ featurestr = strtok(NULL, ",")) {
+ const char *name;
+ const char *val = NULL;
+ char *eq = NULL;
- while (featurestr) {
- char *val;
+ /* Compatibility syntax: */
if (featurestr[0] == '+') {
add_flagname_to_bitmaps(featurestr + 1, plus_features, &local_err);
+ continue;
} else if (featurestr[0] == '-') {
add_flagname_to_bitmaps(featurestr + 1, minus_features, &local_err);
- } else if ((val = strchr(featurestr, '='))) {
- *val = 0; val++;
- feat2prop(featurestr);
- if (!strcmp(featurestr, "xlevel")) {
- char *err;
- char num[32];
-
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- error_setg(errp, "bad numerical value %s", val);
- return;
- }
- if (numvalue < 0x80000000) {
- error_report("xlevel value shall always be >= 0x80000000"
- ", fixup will be removed in future versions");
- numvalue += 0x80000000;
- }
- snprintf(num, sizeof(num), "%" PRIu32, numvalue);
- object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
- } else if (!strcmp(featurestr, "tsc-freq")) {
- int64_t tsc_freq;
- char *err;
- char num[32];
-
- tsc_freq = qemu_strtosz_suffix_unit(val, &err,
- QEMU_STRTOSZ_DEFSUFFIX_B, 1000);
- if (tsc_freq < 0 || *err) {
- error_setg(errp, "bad numerical value %s", val);
- return;
- }
- snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
- object_property_parse(OBJECT(cpu), num, "tsc-frequency",
- &local_err);
- } else if (!strcmp(featurestr, "hv-spinlocks")) {
- char *err;
- const int min = 0xFFF;
- char num[32];
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- error_setg(errp, "bad numerical value %s", val);
- return;
- }
- if (numvalue < min) {
- error_report("hv-spinlocks value shall always be >= 0x%x"
- ", fixup will be removed in future versions",
- min);
- numvalue = min;
- }
- snprintf(num, sizeof(num), "%" PRId32, numvalue);
- object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
- } else {
- object_property_parse(OBJECT(cpu), val, featurestr, &local_err);
- }
- } else {
- feat2prop(featurestr);
- object_property_parse(OBJECT(cpu), "on", featurestr, &local_err);
+ continue;
}
- if (local_err) {
- error_propagate(errp, local_err);
- return;
+
+ eq = strchr(featurestr, '=');
+ if (eq) {
+ *eq++ = 0;
+ val = eq;
+ } else {
+ val = "on";
}
- featurestr = strtok(NULL, ",");
- }
- if (cpu->host_features) {
- for (w = 0; w < FEATURE_WORDS; w++) {
- env->features[w] =
- x86_cpu_get_supported_feature_word(w, cpu->migratable);
+ feat2prop(featurestr);
+ name = featurestr;
+
+ /* Special case: */
+ if (!strcmp(name, "tsc-freq")) {
+ int64_t tsc_freq;
+ char *err;
+ char num[32];
+
+ tsc_freq = qemu_strtosz_suffix_unit(val, &err,
+ QEMU_STRTOSZ_DEFSUFFIX_B, 1000);
+ if (tsc_freq < 0 || *err) {
+ error_setg(errp, "bad numerical value %s", val);
+ return;
+ }
+ snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
+ val = num;
+ name = "tsc-frequency";
}
+
+ object_property_parse(OBJECT(cpu), val, name, &local_err);
}
- for (w = 0; w < FEATURE_WORDS; w++) {
- env->features[w] |= plus_features[w];
- env->features[w] &= ~minus_features[w];
+ if (local_err) {
+ error_propagate(errp, local_err);
}
}
X86CPU *cpu_x86_create(const char *cpu_model, Error **errp)
{
X86CPU *cpu = NULL;
- X86CPUClass *xcc;
ObjectClass *oc;
gchar **model_pieces;
char *name, *features;
error_setg(&error, "Unable to find CPU definition: %s", name);
goto out;
}
- xcc = X86_CPU_CLASS(oc);
-
- if (xcc->kvm_required && !kvm_enabled()) {
- error_setg(&error, "CPU model '%s' requires KVM", name);
- goto out;
- }
cpu = X86_CPU(object_new(object_class_get_name(oc)));
X86CPU *cpu_x86_init(const char *cpu_model)
{
- Error *error = NULL;
- X86CPU *cpu;
-
- cpu = cpu_x86_create(cpu_model, &error);
- if (error) {
- goto out;
- }
-
- object_property_set_bool(OBJECT(cpu), true, "realized", &error);
-
-out:
- if (error) {
- error_report_err(error);
- if (cpu != NULL) {
- object_unref(OBJECT(cpu));
- cpu = NULL;
- }
- }
- return cpu;
+ return X86_CPU(cpu_generic_init(TYPE_X86_CPU, cpu_model));
}
static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
#endif /* !CONFIG_USER_ONLY */
-/* Initialize list of CPU models, filling some non-static fields if necessary
- */
-void x86_cpudef_setup(void)
-{
- int i, j;
- static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" };
-
- for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
- X86CPUDefinition *def = &builtin_x86_defs[i];
-
- /* Look for specific "cpudef" models that */
- /* have the QEMU version in .model_id */
- for (j = 0; j < ARRAY_SIZE(model_with_versions); j++) {
- if (strcmp(model_with_versions[j], def->name) == 0) {
- pstrcpy(def->model_id, sizeof(def->model_id),
- "QEMU Virtual CPU version ");
- pstrcat(def->model_id, sizeof(def->model_id),
- qemu_hw_version());
- break;
- }
- }
- }
-}
-
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
*eax = 0; /* Maximum ECX value for sub-leaves */
*ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */
*ecx = env->features[FEAT_7_0_ECX]; /* Feature flags */
+ if ((*ecx & CPUID_7_0_ECX_PKU) && env->cr[4] & CR4_PKE_MASK) {
+ *ecx |= CPUID_7_0_ECX_OSPKE;
+ }
*edx = 0; /* Reserved */
} else {
*eax = 0;
*edx = 0;
}
break;
+ case 0xB:
+ /* Extended Topology Enumeration Leaf */
+ if (!cpu->enable_cpuid_0xb) {
+ *eax = *ebx = *ecx = *edx = 0;
+ break;
+ }
+
+ *ecx = count & 0xff;
+ *edx = cpu->apic_id;
+
+ switch (count) {
+ case 0:
+ *eax = apicid_core_offset(smp_cores, smp_threads);
+ *ebx = smp_threads;
+ *ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
+ break;
+ case 1:
+ *eax = apicid_pkg_offset(smp_cores, smp_threads);
+ *ebx = smp_cores * smp_threads;
+ *ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
+ break;
+ default:
+ *eax = 0;
+ *ebx = 0;
+ *ecx |= CPUID_TOPOLOGY_LEVEL_INVALID;
+ }
+
+ assert(!(*eax & ~0x1f));
+ *ebx &= 0xffff; /* The count doesn't need to be reliable. */
+ break;
case 0xD: {
KVMState *s = cs->kvm_state;
uint64_t ena_mask;
/* The Linux kernel checks for the CMPLegacy bit and
* discards multiple thread information if it is set.
- * So dont set it here for Intel to make Linux guests happy.
+ * So don't set it here for Intel to make Linux guests happy.
*/
if (cs->nr_cores * cs->nr_threads > 1) {
if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 ||
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
xcr0 |= XSTATE_SSE_MASK;
}
- if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_MPX) {
- xcr0 |= XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK;
+ for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
+ const ExtSaveArea *esa = &x86_ext_save_areas[i];
+ if ((env->features[esa->feature] & esa->bits) == esa->bits) {
+ xcr0 |= 1ull << i;
+ }
}
+
if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK;
}
CPUX86State *env = &cpu->env;
Error *local_err = NULL;
static bool ht_warned;
+ FeatureWord w;
+
+ if (xcc->kvm_required && !kvm_enabled()) {
+ char *name = x86_cpu_class_get_model_name(xcc);
+ error_setg(&local_err, "CPU model '%s' requires KVM", name);
+ g_free(name);
+ goto out;
+ }
if (cpu->apic_id < 0) {
error_setg(errp, "apic-id property was not initialized properly");
return;
}
+ /*TODO: cpu->host_features incorrectly overwrites features
+ * set using "feat=on|off". Once we fix this, we can convert
+ * plus_features & minus_features to global properties
+ * inside x86_cpu_parse_featurestr() too.
+ */
+ if (cpu->host_features) {
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ env->features[w] =
+ x86_cpu_get_supported_feature_word(w, cpu->migratable);
+ }
+ }
+
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ cpu->env.features[w] |= plus_features[w];
+ cpu->env.features[w] &= ~minus_features[w];
+ }
+
if (env->features[FEAT_7_0_EBX] && env->cpuid_level < 7) {
env->cpuid_level = 7;
}
+ if (x86_cpu_filter_features(cpu) && cpu->enforce_cpuid) {
+ error_setg(&local_err,
+ kvm_enabled() ?
+ "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
* CPUID[1].EDX.
*/
}
- if (x86_cpu_filter_features(cpu) && cpu->enforce_cpuid) {
- error_setg(&local_err,
- kvm_enabled() ?
- "Host doesn't support requested features" :
- "TCG doesn't support requested features");
- goto out;
+ cpu_exec_init(cs, &error_abort);
+
+ if (tcg_enabled()) {
+ tcg_x86_init();
}
#ifndef CONFIG_USER_ONLY
X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
CPUX86State *env = &cpu->env;
FeatureWord w;
- static int inited;
cs->env_ptr = env;
- cpu_exec_init(cs, &error_abort);
object_property_add(obj, "family", "int",
x86_cpuid_version_get_family,
}
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
-
- /* init various static tables used in TCG mode */
- if (tcg_enabled() && !inited) {
- inited = 1;
- tcg_x86_init();
- }
}
static int64_t x86_cpu_get_arch_id(CPUState *cs)
DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, 0),
DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0),
DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id),
+ DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true),
DEFINE_PROP_END_OF_LIST()
};