#include "cpu.h"
#include "sysemu/kvm.h"
+#include "sysemu/cpus.h"
+#include "topology.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "sysemu/sysemu.h"
#ifndef CONFIG_USER_ONLY
-#include "hw/xen.h"
+#include "hw/xen/xen.h"
#include "hw/sysbus.h"
-#include "hw/apic_internal.h"
+#include "hw/i386/apic_internal.h"
#endif
+static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
+ uint32_t vendor2, uint32_t vendor3)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ dst[i] = vendor1 >> (8 * i);
+ dst[i + 4] = vendor2 >> (8 * i);
+ dst[i + 8] = vendor3 >> (8 * i);
+ }
+ dst[CPUID_VENDOR_SZ] = '\0';
+}
+
/* feature flags taken from "Intel Processor Identification and the CPUID
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
* between feature naming conventions, aliases may be added.
int check_cpuid = 0;
int enforce_cpuid = 0;
-#if defined(CONFIG_KVM)
static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) |
(1 << KVM_FEATURE_NOP_IO_DELAY) |
(1 << KVM_FEATURE_CLOCKSOURCE2) |
(1 << KVM_FEATURE_ASYNC_PF) |
(1 << KVM_FEATURE_STEAL_TIME) |
+ (1 << KVM_FEATURE_PV_EOI) |
(1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
-static const uint32_t kvm_pv_eoi_features = (0x1 << KVM_FEATURE_PV_EOI);
-#else
-static uint32_t kvm_default_features = 0;
-static const uint32_t kvm_pv_eoi_features = 0;
-#endif
-void enable_kvm_pv_eoi(void)
+void disable_kvm_pv_eoi(void)
{
- kvm_default_features |= kvm_pv_eoi_features;
+ kvm_default_features &= ~(1UL << KVM_FEATURE_PV_EOI);
}
void host_cpuid(uint32_t function, uint32_t count,
}
typedef struct x86_def_t {
- struct x86_def_t *next;
const char *name;
uint32_t level;
- uint32_t vendor1, vendor2, vendor3;
+ /* vendor is zero-terminated, 12 character ASCII string */
+ char vendor[CPUID_VENDOR_SZ + 1];
int family;
int model;
int stepping;
- int tsc_khz;
uint32_t features, ext_features, ext2_features, ext3_features;
uint32_t kvm_features, svm_features;
uint32_t xlevel;
char model_id[48];
- int vendor_override;
/* Store the results of Centaur's CPUID instructions */
uint32_t ext4_features;
uint32_t xlevel2;
CPUID_PSE36 (needed for Solaris) */
/* missing:
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
-#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | \
- CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT | \
- CPUID_EXT_HYPERVISOR)
+#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | \
+ CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | \
+ CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \
+ CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR)
/* missing:
- CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST,
- CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_XSAVE */
+ CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX,
+ CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA,
+ CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA,
+ CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_XSAVE,
+ CPUID_EXT_OSXSAVE, CPUID_EXT_AVX, CPUID_EXT_F16C,
+ CPUID_EXT_RDRAND */
#define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \
CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT)
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
#define TCG_SVM_FEATURES 0
-#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP)
-
-/* maintains list of cpu model definitions
- */
-static x86_def_t *x86_defs = {NULL};
+#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP \
+ CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX)
+ /* missing:
+ CPUID_7_0_EBX_FSGSBASE, 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 */
-/* built-in cpu model definitions (deprecated)
+/* built-in CPU model definitions
*/
static x86_def_t builtin_x86_defs[] = {
{
.name = "qemu64",
.level = 4,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 6,
.model = 2,
.stepping = 3,
{
.name = "phenom",
.level = 5,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 16,
.model = 2,
.stepping = 3,
{
.name = "core2duo",
.level = 10,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 15,
.stepping = 11,
{
.name = "kvm64",
.level = 5,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 15,
.model = 6,
.stepping = 1,
{
.name = "qemu32",
.level = 4,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 3,
.stepping = 3,
{
.name = "kvm32",
.level = 5,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 15,
.model = 6,
.stepping = 1,
{
.name = "coreduo",
.level = 10,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 14,
.stepping = 8,
{
.name = "486",
.level = 1,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 4,
.model = 0,
.stepping = 0,
{
.name = "pentium",
.level = 1,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 5,
.model = 4,
.stepping = 3,
{
.name = "pentium2",
.level = 2,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 5,
.stepping = 2,
{
.name = "pentium3",
.level = 2,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 7,
.stepping = 3,
{
.name = "athlon",
.level = 2,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 6,
.model = 2,
.stepping = 3,
.name = "n270",
/* original is on level 10 */
.level = 5,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 28,
.stepping = 2,
{
.name = "Conroe",
.level = 2,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 2,
.stepping = 3,
{
.name = "Penryn",
.level = 2,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 2,
.stepping = 3,
{
.name = "Nehalem",
.level = 2,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 2,
.stepping = 3,
{
.name = "Westmere",
.level = 11,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 44,
.stepping = 1,
CPUID_DE | CPUID_FP87,
.ext_features = CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
- CPUID_EXT_SSE3,
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
.ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
.ext3_features = CPUID_EXT3_LAHF_LM,
.xlevel = 0x8000000A,
{
.name = "SandyBridge",
.level = 0xd,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 42,
.stepping = 1,
{
.name = "Haswell",
.level = 0xd,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
+ .vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 60,
.stepping = 1,
{
.name = "Opteron_G1",
.level = 5,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 15,
.model = 6,
.stepping = 1,
{
.name = "Opteron_G2",
.level = 5,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 15,
.model = 6,
.stepping = 1,
{
.name = "Opteron_G3",
.level = 5,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 15,
.model = 6,
.stepping = 1,
{
.name = "Opteron_G4",
.level = 0xd,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 21,
.model = 1,
.stepping = 2,
{
.name = "Opteron_G5",
.level = 0xd,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
+ .vendor = CPUID_VENDOR_AMD,
.family = 21,
.model = 2,
.stepping = 0,
x86_cpu_def->name = "host";
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->vendor1 = ebx;
- x86_cpu_def->vendor2 = edx;
- x86_cpu_def->vendor3 = ecx;
+ x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
cpu_x86_fill_model_id(x86_cpu_def->model_id);
- x86_cpu_def->vendor_override = 0;
/* Call Centaur's CPUID instruction. */
- if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
- x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
- x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
+ if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) {
host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
if (eax >= 0xC0000001) {
return 0;
}
-/* best effort attempt to inform user requested cpu flags aren't making
- * their way to the guest.
+/* Check if all requested cpu flags are making their way to the guest
+ *
+ * Returns 0 if all flags are supported by the host, non-zero otherwise.
*
* This function may be called only if KVM is enabled.
*/
-static int kvm_check_features_against_host(x86_def_t *guest_def)
+static int kvm_check_features_against_host(X86CPU *cpu)
{
+ CPUX86State *env = &cpu->env;
x86_def_t host_def;
uint32_t mask;
int rv, i;
struct model_features_t ft[] = {
- {&guest_def->features, &host_def.features,
+ {&env->cpuid_features, &host_def.features,
FEAT_1_EDX },
- {&guest_def->ext_features, &host_def.ext_features,
+ {&env->cpuid_ext_features, &host_def.ext_features,
FEAT_1_ECX },
- {&guest_def->ext2_features, &host_def.ext2_features,
+ {&env->cpuid_ext2_features, &host_def.ext2_features,
FEAT_8000_0001_EDX },
- {&guest_def->ext3_features, &host_def.ext3_features,
+ {&env->cpuid_ext3_features, &host_def.ext3_features,
FEAT_8000_0001_ECX },
+ {&env->cpuid_ext4_features, &host_def.ext4_features,
+ FEAT_C000_0001_EDX },
+ {&env->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features,
+ FEAT_7_0_EBX },
+ {&env->cpuid_svm_features, &host_def.svm_features,
+ FEAT_SVM },
+ {&env->cpuid_kvm_features, &host_def.kvm_features,
+ FEAT_KVM },
};
assert(kvm_enabled());
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
char *value;
- int i;
value = (char *)g_malloc(CPUID_VENDOR_SZ + 1);
- for (i = 0; i < 4; i++) {
- value[i ] = env->cpuid_vendor1 >> (8 * i);
- value[i + 4] = env->cpuid_vendor2 >> (8 * i);
- value[i + 8] = env->cpuid_vendor3 >> (8 * i);
- }
- value[CPUID_VENDOR_SZ] = '\0';
+ x86_cpu_vendor_words2str(value, env->cpuid_vendor1, env->cpuid_vendor2,
+ env->cpuid_vendor3);
return value;
}
env->cpuid_vendor2 |= ((uint8_t)value[i + 4]) << (8 * i);
env->cpuid_vendor3 |= ((uint8_t)value[i + 8]) << (8 * i);
}
- env->cpuid_vendor_override = 1;
}
static char *x86_cpuid_get_model_id(Object *obj, Error **errp)
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
{
x86_def_t *def;
+ int i;
- for (def = x86_defs; def; def = def->next) {
- if (name && !strcmp(name, def->name)) {
- break;
- }
+ if (name == NULL) {
+ return -1;
}
- if (kvm_enabled() && name && strcmp(name, "host") == 0) {
+ if (kvm_enabled() && strcmp(name, "host") == 0) {
kvm_cpu_fill_host(x86_cpu_def);
- } else if (!def) {
- return -1;
- } else {
- memcpy(x86_cpu_def, def, sizeof(*def));
+ return 0;
}
- return 0;
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
+ def = &builtin_x86_defs[i];
+ if (strcmp(name, def->name) == 0) {
+ memcpy(x86_cpu_def, def, sizeof(*def));
+ /* sysenter isn't supported in compatibility mode on AMD,
+ * syscall isn't supported in compatibility mode on Intel.
+ * Normally we advertise the actual CPU vendor, but you can
+ * override this using the 'vendor' property if you want to use
+ * KVM's sysenter/syscall emulation in compatibility mode and
+ * when doing cross vendor migration
+ */
+ if (kvm_enabled()) {
+ uint32_t ebx = 0, ecx = 0, edx = 0;
+ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
+ x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
+ }
+ return 0;
+ }
+ }
+
+ return -1;
}
/* Parse "+feature,-feature,feature=foo" CPU feature string
*/
-static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features)
+static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp)
{
- unsigned int i;
char *featurestr; /* Single 'key=value" string being parsed */
/* Features to be added */
- FeatureWordArray plus_features = {
- [FEAT_KVM] = kvm_default_features,
- };
+ FeatureWordArray plus_features = { 0 };
/* Features to be removed */
FeatureWordArray minus_features = { 0 };
uint32_t numvalue;
-
- add_flagname_to_bitmaps("hypervisor", plus_features);
+ CPUX86State *env = &cpu->env;
featurestr = features ? strtok(features, ",") : NULL;
} else if ((val = strchr(featurestr, '='))) {
*val = 0; val++;
if (!strcmp(featurestr, "family")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err || numvalue > 0xff + 0xf) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->family = numvalue;
+ object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "model")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err || numvalue > 0xff) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->model = numvalue;
+ object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "stepping")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err || numvalue > 0xf) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->stepping = numvalue ;
+ object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "level")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->level = numvalue;
+ object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "xlevel")) {
char *err;
+ char num[32];
+
numvalue = strtoul(val, &err, 0);
if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
+ error_setg(errp, "bad numerical value %s", val);
+ goto out;
}
if (numvalue < 0x80000000) {
+ fprintf(stderr, "xlevel value shall always be >= 0x80000000"
+ ", fixup will be removed in future versions\n");
numvalue += 0x80000000;
}
- x86_cpu_def->xlevel = numvalue;
+ snprintf(num, sizeof(num), "%" PRIu32, numvalue);
+ object_property_parse(OBJECT(cpu), num, featurestr, errp);
} else if (!strcmp(featurestr, "vendor")) {
- if (strlen(val) != 12) {
- fprintf(stderr, "vendor string must be 12 chars long\n");
- goto error;
- }
- x86_cpu_def->vendor1 = 0;
- x86_cpu_def->vendor2 = 0;
- x86_cpu_def->vendor3 = 0;
- for(i = 0; i < 4; i++) {
- x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i);
- x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i);
- x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i);
- }
- x86_cpu_def->vendor_override = 1;
+ object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "model_id")) {
- pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
- val);
+ object_property_parse(OBJECT(cpu), val, "model-id", errp);
} else if (!strcmp(featurestr, "tsc_freq")) {
int64_t tsc_freq;
char *err;
+ char num[32];
tsc_freq = strtosz_suffix_unit(val, &err,
STRTOSZ_DEFSUFFIX_B, 1000);
if (tsc_freq < 0 || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
+ error_setg(errp, "bad numerical value %s", val);
+ goto out;
}
- x86_cpu_def->tsc_khz = tsc_freq / 1000;
+ snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
+ object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp);
} else if (!strcmp(featurestr, "hv_spinlocks")) {
char *err;
numvalue = strtoul(val, &err, 0);
if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
+ error_setg(errp, "bad numerical value %s", val);
+ goto out;
}
hyperv_set_spinlock_retries(numvalue);
} else {
- fprintf(stderr, "unrecognized feature %s\n", featurestr);
- goto error;
+ error_setg(errp, "unrecognized feature %s", featurestr);
+ goto out;
}
} else if (!strcmp(featurestr, "check")) {
check_cpuid = 1;
} else if (!strcmp(featurestr, "hv_vapic")) {
hyperv_enable_vapic_recommended(true);
} else {
- fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
- goto error;
+ error_setg(errp, "feature string `%s' not in format (+feature|"
+ "-feature|feature=xyz)", featurestr);
+ goto out;
+ }
+ if (error_is_set(errp)) {
+ goto out;
}
featurestr = strtok(NULL, ",");
}
- x86_cpu_def->features |= plus_features[FEAT_1_EDX];
- x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX];
- x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX];
- x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX];
- x86_cpu_def->ext4_features |= plus_features[FEAT_C000_0001_EDX];
- x86_cpu_def->kvm_features |= plus_features[FEAT_KVM];
- x86_cpu_def->svm_features |= plus_features[FEAT_SVM];
- x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX];
- x86_cpu_def->features &= ~minus_features[FEAT_1_EDX];
- x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX];
- x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX];
- x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX];
- x86_cpu_def->ext4_features &= ~minus_features[FEAT_C000_0001_EDX];
- x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM];
- x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM];
- x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX];
- if (check_cpuid && kvm_enabled()) {
- if (kvm_check_features_against_host(x86_cpu_def) && enforce_cpuid)
- goto error;
- }
- return 0;
-
-error:
- return -1;
+ env->cpuid_features |= plus_features[FEAT_1_EDX];
+ env->cpuid_ext_features |= plus_features[FEAT_1_ECX];
+ env->cpuid_ext2_features |= plus_features[FEAT_8000_0001_EDX];
+ env->cpuid_ext3_features |= plus_features[FEAT_8000_0001_ECX];
+ env->cpuid_ext4_features |= plus_features[FEAT_C000_0001_EDX];
+ env->cpuid_kvm_features |= plus_features[FEAT_KVM];
+ env->cpuid_svm_features |= plus_features[FEAT_SVM];
+ env->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX];
+ env->cpuid_features &= ~minus_features[FEAT_1_EDX];
+ env->cpuid_ext_features &= ~minus_features[FEAT_1_ECX];
+ env->cpuid_ext2_features &= ~minus_features[FEAT_8000_0001_EDX];
+ env->cpuid_ext3_features &= ~minus_features[FEAT_8000_0001_ECX];
+ env->cpuid_ext4_features &= ~minus_features[FEAT_C000_0001_EDX];
+ env->cpuid_kvm_features &= ~minus_features[FEAT_KVM];
+ env->cpuid_svm_features &= ~minus_features[FEAT_SVM];
+ env->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX];
+
+out:
+ return;
}
/* generate a composite string into buf of all cpuid names in featureset
{
x86_def_t *def;
char buf[256];
+ int i;
- for (def = x86_defs; def; def = def->next) {
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
+ def = &builtin_x86_defs[i];
snprintf(buf, sizeof(buf), "%s", def->name);
(*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
}
- if (kvm_enabled()) {
- (*cpu_fprintf)(f, "x86 %16s\n", "[host]");
- }
+#ifdef CONFIG_KVM
+ (*cpu_fprintf)(f, "x86 %16s %-48s\n", "host",
+ "KVM processor with all supported host features "
+ "(only available in KVM mode)");
+#endif
+
(*cpu_fprintf)(f, "\nRecognized CPUID flags:\n");
- listflags(buf, sizeof(buf), (uint32_t)~0, feature_name, 1);
- (*cpu_fprintf)(f, " %s\n", buf);
- listflags(buf, sizeof(buf), (uint32_t)~0, ext_feature_name, 1);
- (*cpu_fprintf)(f, " %s\n", buf);
- listflags(buf, sizeof(buf), (uint32_t)~0, ext2_feature_name, 1);
- (*cpu_fprintf)(f, " %s\n", buf);
- listflags(buf, sizeof(buf), (uint32_t)~0, ext3_feature_name, 1);
- (*cpu_fprintf)(f, " %s\n", buf);
+ for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) {
+ FeatureWordInfo *fw = &feature_word_info[i];
+
+ listflags(buf, sizeof(buf), (uint32_t)~0, fw->feat_names, 1);
+ (*cpu_fprintf)(f, " %s\n", buf);
+ }
}
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
CpuDefinitionInfoList *cpu_list = NULL;
x86_def_t *def;
+ int i;
- for (def = x86_defs; def; def = def->next) {
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
+ def = &builtin_x86_defs[i];
info = g_malloc0(sizeof(*info));
info->name = g_strdup(def->name);
}
#endif
-int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
+static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
{
CPUX86State *env = &cpu->env;
x86_def_t def1, *def = &def1;
- Error *error = NULL;
- char *name, *features;
- gchar **model_pieces;
memset(def, 0, sizeof(*def));
- model_pieces = g_strsplit(cpu_model, ",", 2);
- if (!model_pieces[0]) {
- goto error;
- }
- name = model_pieces[0];
- features = model_pieces[1];
-
if (cpu_x86_find_by_name(def, name) < 0) {
- goto error;
+ error_setg(errp, "Unable to find CPU definition: %s", name);
+ return;
}
- if (cpu_x86_parse_featurestr(def, features) < 0) {
- goto error;
+ if (kvm_enabled()) {
+ def->kvm_features |= kvm_default_features;
}
- assert(def->vendor1);
- env->cpuid_vendor1 = def->vendor1;
- env->cpuid_vendor2 = def->vendor2;
- env->cpuid_vendor3 = def->vendor3;
- env->cpuid_vendor_override = def->vendor_override;
- object_property_set_int(OBJECT(cpu), def->level, "level", &error);
- object_property_set_int(OBJECT(cpu), def->family, "family", &error);
- object_property_set_int(OBJECT(cpu), def->model, "model", &error);
- object_property_set_int(OBJECT(cpu), def->stepping, "stepping", &error);
+ def->ext_features |= CPUID_EXT_HYPERVISOR;
+
+ object_property_set_str(OBJECT(cpu), def->vendor, "vendor", errp);
+ object_property_set_int(OBJECT(cpu), def->level, "level", errp);
+ object_property_set_int(OBJECT(cpu), def->family, "family", errp);
+ object_property_set_int(OBJECT(cpu), def->model, "model", errp);
+ object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp);
env->cpuid_features = def->features;
env->cpuid_ext_features = def->ext_features;
env->cpuid_ext2_features = def->ext2_features;
env->cpuid_ext3_features = def->ext3_features;
- object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", &error);
+ object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", errp);
env->cpuid_kvm_features = def->kvm_features;
env->cpuid_svm_features = def->svm_features;
env->cpuid_ext4_features = def->ext4_features;
env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features;
env->cpuid_xlevel2 = def->xlevel2;
- object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
- "tsc-frequency", &error);
- object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error);
+ object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
+}
+
+X86CPU *cpu_x86_init(const char *cpu_model)
+{
+ X86CPU *cpu = NULL;
+ CPUX86State *env;
+ gchar **model_pieces;
+ char *name, *features;
+ Error *error = NULL;
+
+ model_pieces = g_strsplit(cpu_model, ",", 2);
+ if (!model_pieces[0]) {
+ error_setg(&error, "Invalid/empty CPU model name");
+ goto out;
+ }
+ name = model_pieces[0];
+ features = model_pieces[1];
+
+ cpu = X86_CPU(object_new(TYPE_X86_CPU));
+ env = &cpu->env;
+ env->cpu_model_str = cpu_model;
+
+ cpu_x86_register(cpu, name, &error);
if (error) {
- fprintf(stderr, "%s\n", error_get_pretty(error));
- error_free(error);
- goto error;
+ goto out;
}
+ cpu_x86_parse_featurestr(cpu, features, &error);
+ if (error) {
+ goto out;
+ }
+
+ object_property_set_bool(OBJECT(cpu), true, "realized", &error);
+ if (error) {
+ goto out;
+ }
+
+out:
g_strfreev(model_pieces);
- return 0;
-error:
- g_strfreev(model_pieces);
- return -1;
+ if (error) {
+ fprintf(stderr, "%s\n", error_get_pretty(error));
+ error_free(error);
+ if (cpu != NULL) {
+ object_unref(OBJECT(cpu));
+ cpu = NULL;
+ }
+ }
+ return cpu;
}
#if !defined(CONFIG_USER_ONLY)
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
x86_def_t *def = &builtin_x86_defs[i];
- def->next = x86_defs;
/* Look for specific "cpudef" models that */
/* have the QEMU version in .model_id */
break;
}
}
-
- x86_defs = def;
}
}
*ebx = env->cpuid_vendor1;
*edx = env->cpuid_vendor2;
*ecx = env->cpuid_vendor3;
-
- /* sysenter isn't supported on compatibility mode on AMD, syscall
- * isn't supported in compatibility mode on Intel.
- * Normally we advertise the actual cpu vendor, but you can override
- * this if you want to use KVM's sysenter/syscall emulation
- * in compatibility mode and when doing cross vendor migration
- */
- if (kvm_enabled() && ! env->cpuid_vendor_override) {
- host_cpuid(0, 0, NULL, ebx, ecx, edx);
- }
}
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
apic_designate_bsp(env->apic_state);
}
- env->halted = !cpu_is_bsp(cpu);
+ s->halted = !cpu_is_bsp(cpu);
#endif
}
}
}
-#define MSI_ADDR_BASE 0xfee00000
-
#ifndef CONFIG_USER_ONLY
static void x86_cpu_apic_init(X86CPU *cpu, Error **errp)
{
/* NOTE: the APIC is directly connected to the CPU - it is not
on the global memory bus. */
/* XXX: what if the base changes? */
- sysbus_mmio_map(sysbus_from_qdev(env->apic_state), 0, MSI_ADDR_BASE);
+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(env->apic_state), 0,
+ APIC_DEFAULT_ADDRESS, 0x1000);
apic_mapped = 1;
}
}
#endif
-void x86_cpu_realize(Object *obj, Error **errp)
+static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
{
- X86CPU *cpu = X86_CPU(obj);
+ X86CPU *cpu = X86_CPU(dev);
+ X86CPUClass *xcc = X86_CPU_GET_CLASS(dev);
CPUX86State *env = &cpu->env;
+ Error *local_err = NULL;
if (env->cpuid_7_0_ebx_features && env->cpuid_level < 7) {
env->cpuid_level = 7;
env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
env->cpuid_svm_features &= TCG_SVM_FEATURES;
} else {
+ if (check_cpuid && kvm_check_features_against_host(cpu)
+ && enforce_cpuid) {
+ error_setg(&local_err,
+ "Host's CPU doesn't support requested features");
+ goto out;
+ }
#ifdef CONFIG_KVM
filter_features_for_kvm(cpu);
#endif
qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
if (cpu->env.cpuid_features & CPUID_APIC || smp_cpus > 1) {
- x86_cpu_apic_init(cpu, errp);
- if (error_is_set(errp)) {
- return;
+ x86_cpu_apic_init(cpu, &local_err);
+ if (local_err != NULL) {
+ goto out;
}
}
#endif
mce_init(cpu);
qemu_init_vcpu(&cpu->env);
cpu_reset(CPU(cpu));
+
+ xcc->parent_realize(dev, &local_err);
+out:
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+}
+
+/* Enables contiguous-apic-ID mode, for compatibility */
+static bool compat_apic_id_mode;
+
+void enable_compat_apic_id_mode(void)
+{
+ compat_apic_id_mode = true;
+}
+
+/* Calculates initial APIC ID for a specific CPU index
+ *
+ * Currently we need to be able to calculate the APIC ID from the CPU index
+ * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
+ * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
+ * all CPUs up to max_cpus.
+ */
+uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
+{
+ uint32_t correct_id;
+ static bool warned;
+
+ correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index);
+ if (compat_apic_id_mode) {
+ if (cpu_index != correct_id && !warned) {
+ error_report("APIC IDs set in compatibility mode, "
+ "CPU topology won't match the configuration");
+ warned = true;
+ }
+ return cpu_index;
+ } else {
+ return correct_id;
+ }
}
static void x86_cpu_initfn(Object *obj)
CPUX86State *env = &cpu->env;
static int inited;
+ cs->env_ptr = env;
cpu_exec_init(env);
object_property_add(obj, "family", "int",
x86_cpuid_get_tsc_freq,
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
- env->cpuid_apic_id = cs->cpu_index;
+ env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
/* init various static tables used in TCG mode */
if (tcg_enabled() && !inited) {
{
X86CPUClass *xcc = X86_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ xcc->parent_realize = dc->realize;
+ dc->realize = x86_cpu_realizefn;
xcc->parent_reset = cc->reset;
cc->reset = x86_cpu_reset;
+
+ cc->do_interrupt = x86_cpu_do_interrupt;
+ cpu_class_set_vmsd(cc, &vmstate_x86_cpu);
}
static const TypeInfo x86_cpu_type_info = {