2010-03-11 14:38:55 +01:00
|
|
|
/*
|
|
|
|
* i386 CPUID helper functions
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
|
|
|
#include "cpu.h"
|
2012-12-17 18:20:04 +01:00
|
|
|
#include "sysemu/kvm.h"
|
2013-01-22 21:25:09 +01:00
|
|
|
#include "sysemu/cpus.h"
|
2013-03-20 13:11:56 +01:00
|
|
|
#include "kvm_i386.h"
|
2013-01-22 21:25:09 +01:00
|
|
|
#include "topology.h"
|
2010-03-11 14:38:55 +01:00
|
|
|
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/option.h"
|
|
|
|
#include "qemu/config-file.h"
|
2012-12-17 18:19:43 +01:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2010-03-11 14:38:55 +01:00
|
|
|
|
2013-05-06 18:20:07 +02:00
|
|
|
#include "qapi-types.h"
|
|
|
|
#include "qapi-visit.h"
|
2012-12-17 18:19:43 +01:00
|
|
|
#include "qapi/visitor.h"
|
2012-12-17 18:20:04 +01:00
|
|
|
#include "sysemu/arch_init.h"
|
2012-04-17 12:10:29 +02:00
|
|
|
|
2012-07-23 15:22:28 +02:00
|
|
|
#include "hw/hw.h"
|
2012-08-30 22:28:31 +02:00
|
|
|
#if defined(CONFIG_KVM)
|
2012-08-29 16:32:41 +02:00
|
|
|
#include <linux/kvm_para.h>
|
2012-08-30 22:28:31 +02:00
|
|
|
#endif
|
2012-07-23 15:22:28 +02:00
|
|
|
|
2012-12-17 18:20:04 +01:00
|
|
|
#include "sysemu/sysemu.h"
|
2013-04-29 19:03:01 +02:00
|
|
|
#include "hw/qdev-properties.h"
|
2013-04-29 18:54:13 +02:00
|
|
|
#include "hw/cpu/icc_bus.h"
|
2012-10-13 22:35:39 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2013-02-05 17:06:20 +01:00
|
|
|
#include "hw/xen/xen.h"
|
|
|
|
#include "hw/i386/apic_internal.h"
|
2012-10-13 22:35:39 +02:00
|
|
|
#endif
|
|
|
|
|
2013-08-27 17:24:37 +02:00
|
|
|
|
|
|
|
/* Cache topology CPUID constants: */
|
|
|
|
|
|
|
|
/* CPUID Leaf 2 Descriptors */
|
|
|
|
|
|
|
|
#define CPUID_2_L1D_32KB_8WAY_64B 0x2c
|
|
|
|
#define CPUID_2_L1I_32KB_8WAY_64B 0x30
|
|
|
|
#define CPUID_2_L2_2MB_8WAY_64B 0x7d
|
|
|
|
|
|
|
|
|
|
|
|
/* CPUID Leaf 4 constants: */
|
|
|
|
|
|
|
|
/* EAX: */
|
|
|
|
#define CPUID_4_TYPE_DCACHE 1
|
|
|
|
#define CPUID_4_TYPE_ICACHE 2
|
|
|
|
#define CPUID_4_TYPE_UNIFIED 3
|
|
|
|
|
|
|
|
#define CPUID_4_LEVEL(l) ((l) << 5)
|
|
|
|
|
|
|
|
#define CPUID_4_SELF_INIT_LEVEL (1 << 8)
|
|
|
|
#define CPUID_4_FULLY_ASSOC (1 << 9)
|
|
|
|
|
|
|
|
/* EDX: */
|
|
|
|
#define CPUID_4_NO_INVD_SHARING (1 << 0)
|
|
|
|
#define CPUID_4_INCLUSIVE (1 << 1)
|
|
|
|
#define CPUID_4_COMPLEX_IDX (1 << 2)
|
|
|
|
|
|
|
|
#define ASSOC_FULL 0xFF
|
|
|
|
|
|
|
|
/* AMD associativity encoding used on CPUID Leaf 0x80000006: */
|
|
|
|
#define AMD_ENC_ASSOC(a) (a <= 1 ? a : \
|
|
|
|
a == 2 ? 0x2 : \
|
|
|
|
a == 4 ? 0x4 : \
|
|
|
|
a == 8 ? 0x6 : \
|
|
|
|
a == 16 ? 0x8 : \
|
|
|
|
a == 32 ? 0xA : \
|
|
|
|
a == 48 ? 0xB : \
|
|
|
|
a == 64 ? 0xC : \
|
|
|
|
a == 96 ? 0xD : \
|
|
|
|
a == 128 ? 0xE : \
|
|
|
|
a == ASSOC_FULL ? 0xF : \
|
|
|
|
0 /* invalid value */)
|
|
|
|
|
|
|
|
|
|
|
|
/* Definitions of the hardcoded cache entries we expose: */
|
|
|
|
|
|
|
|
/* L1 data cache: */
|
|
|
|
#define L1D_LINE_SIZE 64
|
|
|
|
#define L1D_ASSOCIATIVITY 8
|
|
|
|
#define L1D_SETS 64
|
|
|
|
#define L1D_PARTITIONS 1
|
|
|
|
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
|
|
|
|
#define L1D_DESCRIPTOR CPUID_2_L1D_32KB_8WAY_64B
|
|
|
|
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
|
|
|
|
#define L1D_LINES_PER_TAG 1
|
|
|
|
#define L1D_SIZE_KB_AMD 64
|
|
|
|
#define L1D_ASSOCIATIVITY_AMD 2
|
|
|
|
|
|
|
|
/* L1 instruction cache: */
|
|
|
|
#define L1I_LINE_SIZE 64
|
|
|
|
#define L1I_ASSOCIATIVITY 8
|
|
|
|
#define L1I_SETS 64
|
|
|
|
#define L1I_PARTITIONS 1
|
|
|
|
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
|
|
|
|
#define L1I_DESCRIPTOR CPUID_2_L1I_32KB_8WAY_64B
|
|
|
|
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
|
|
|
|
#define L1I_LINES_PER_TAG 1
|
|
|
|
#define L1I_SIZE_KB_AMD 64
|
|
|
|
#define L1I_ASSOCIATIVITY_AMD 2
|
|
|
|
|
|
|
|
/* Level 2 unified cache: */
|
|
|
|
#define L2_LINE_SIZE 64
|
|
|
|
#define L2_ASSOCIATIVITY 16
|
|
|
|
#define L2_SETS 4096
|
|
|
|
#define L2_PARTITIONS 1
|
|
|
|
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 4MiB */
|
|
|
|
/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */
|
|
|
|
#define L2_DESCRIPTOR CPUID_2_L2_2MB_8WAY_64B
|
|
|
|
/*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */
|
|
|
|
#define L2_LINES_PER_TAG 1
|
|
|
|
#define L2_SIZE_KB_AMD 512
|
|
|
|
|
|
|
|
/* No L3 cache: */
|
|
|
|
#define L3_SIZE_KB 0 /* disabled */
|
|
|
|
#define L3_ASSOCIATIVITY 0 /* disabled */
|
|
|
|
#define L3_LINES_PER_TAG 0 /* disabled */
|
|
|
|
#define L3_LINE_SIZE 0 /* disabled */
|
|
|
|
|
|
|
|
/* TLB definitions: */
|
|
|
|
|
|
|
|
#define L1_DTLB_2M_ASSOC 1
|
|
|
|
#define L1_DTLB_2M_ENTRIES 255
|
|
|
|
#define L1_DTLB_4K_ASSOC 1
|
|
|
|
#define L1_DTLB_4K_ENTRIES 255
|
|
|
|
|
|
|
|
#define L1_ITLB_2M_ASSOC 1
|
|
|
|
#define L1_ITLB_2M_ENTRIES 255
|
|
|
|
#define L1_ITLB_4K_ASSOC 1
|
|
|
|
#define L1_ITLB_4K_ENTRIES 255
|
|
|
|
|
|
|
|
#define L2_DTLB_2M_ASSOC 0 /* disabled */
|
|
|
|
#define L2_DTLB_2M_ENTRIES 0 /* disabled */
|
|
|
|
#define L2_DTLB_4K_ASSOC 4
|
|
|
|
#define L2_DTLB_4K_ENTRIES 512
|
|
|
|
|
|
|
|
#define L2_ITLB_2M_ASSOC 0 /* disabled */
|
|
|
|
#define L2_ITLB_2M_ENTRIES 0 /* disabled */
|
|
|
|
#define L2_ITLB_4K_ASSOC 4
|
|
|
|
#define L2_ITLB_4K_ENTRIES 512
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-01-21 15:06:36 +01:00
|
|
|
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';
|
|
|
|
}
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
static const char *feature_name[] = {
|
|
|
|
"fpu", "vme", "de", "pse",
|
|
|
|
"tsc", "msr", "pae", "mce",
|
|
|
|
"cx8", "apic", NULL, "sep",
|
|
|
|
"mtrr", "pge", "mca", "cmov",
|
|
|
|
"pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
|
|
|
|
NULL, "ds" /* Intel dts */, "acpi", "mmx",
|
|
|
|
"fxsr", "sse", "sse2", "ss",
|
|
|
|
"ht" /* Intel htt */, "tm", "ia64", "pbe",
|
|
|
|
};
|
|
|
|
static const char *ext_feature_name[] = {
|
2012-02-17 17:41:20 +01:00
|
|
|
"pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor",
|
2010-03-11 14:38:59 +01:00
|
|
|
"ds_cpl", "vmx", "smx", "est",
|
2010-03-11 14:38:55 +01:00
|
|
|
"tm2", "ssse3", "cid", NULL,
|
2010-03-11 14:38:59 +01:00
|
|
|
"fma", "cx16", "xtpr", "pdcm",
|
2012-07-20 09:08:21 +02:00
|
|
|
NULL, "pcid", "dca", "sse4.1|sse4_1",
|
2010-03-11 14:38:59 +01:00
|
|
|
"sse4.2|sse4_2", "x2apic", "movbe", "popcnt",
|
2012-03-06 19:11:30 +01:00
|
|
|
"tsc-deadline", "aes", "xsave", "osxsave",
|
target-i386/cpu: Name new CPUID bits
Update QEMU's knowledge of CPUID bit names. This allows to
enable/disable those new features on QEMU's command line when
using KVM and prepares future feature enablement in QEMU.
This adds F16C, RDRAND, LWP, TBM, TopoExt, PerfCtr_Core, PerfCtr_NB,
FSGSBASE, BMI1, AVX2, BMI2, ERMS, PCID, InvPCID, RTM, RDSeed and ADX.
Sources where the AMD BKDG for Family 15h/Model 10h, Intel Software
Developer Manual, and the Linux kernel for the leaf 7 bits.
Signed-off-by: Andre Przywara <osp@andrep.de>
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@amd.com>
[ehabkost: added CPUID_EXT_PCID]
[ehabkost: edited commit message]
[ehabkost: rebased against latest qemu.git master]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 19:28:52 +01:00
|
|
|
"avx", "f16c", "rdrand", "hypervisor",
|
2010-03-11 14:38:55 +01:00
|
|
|
};
|
2012-09-06 12:05:38 +02:00
|
|
|
/* Feature names that are already defined on feature_name[] but are set on
|
|
|
|
* CPUID[8000_0001].EDX on AMD CPUs don't have their names on
|
|
|
|
* ext2_feature_name[]. They are copied automatically to cpuid_ext2_features
|
|
|
|
* if and only if CPU vendor is AMD.
|
|
|
|
*/
|
2010-03-11 14:38:55 +01:00
|
|
|
static const char *ext2_feature_name[] = {
|
2012-09-06 12:05:38 +02:00
|
|
|
NULL /* fpu */, NULL /* vme */, NULL /* de */, NULL /* pse */,
|
|
|
|
NULL /* tsc */, NULL /* msr */, NULL /* pae */, NULL /* mce */,
|
|
|
|
NULL /* cx8 */ /* AMD CMPXCHG8B */, NULL /* apic */, NULL, "syscall",
|
|
|
|
NULL /* mtrr */, NULL /* pge */, NULL /* mca */, NULL /* cmov */,
|
|
|
|
NULL /* pat */, NULL /* pse36 */, NULL, NULL /* Linux mp */,
|
|
|
|
"nx|xd", NULL, "mmxext", NULL /* mmx */,
|
|
|
|
NULL /* fxsr */, "fxsr_opt|ffxsr", "pdpe1gb" /* AMD Page1GB */, "rdtscp",
|
2012-10-24 16:10:33 +02:00
|
|
|
NULL, "lm|i64", "3dnowext", "3dnow",
|
2010-03-11 14:38:55 +01:00
|
|
|
};
|
|
|
|
static const char *ext3_feature_name[] = {
|
|
|
|
"lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
|
|
|
|
"cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
|
2010-03-11 14:38:59 +01:00
|
|
|
"3dnowprefetch", "osvw", "ibs", "xop",
|
target-i386/cpu: Name new CPUID bits
Update QEMU's knowledge of CPUID bit names. This allows to
enable/disable those new features on QEMU's command line when
using KVM and prepares future feature enablement in QEMU.
This adds F16C, RDRAND, LWP, TBM, TopoExt, PerfCtr_Core, PerfCtr_NB,
FSGSBASE, BMI1, AVX2, BMI2, ERMS, PCID, InvPCID, RTM, RDSeed and ADX.
Sources where the AMD BKDG for Family 15h/Model 10h, Intel Software
Developer Manual, and the Linux kernel for the leaf 7 bits.
Signed-off-by: Andre Przywara <osp@andrep.de>
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@amd.com>
[ehabkost: added CPUID_EXT_PCID]
[ehabkost: edited commit message]
[ehabkost: rebased against latest qemu.git master]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 19:28:52 +01:00
|
|
|
"skinit", "wdt", NULL, "lwp",
|
|
|
|
"fma4", "tce", NULL, "nodeid_msr",
|
|
|
|
NULL, "tbm", "topoext", "perfctr_core",
|
|
|
|
"perfctr_nb", NULL, NULL, NULL,
|
2010-03-11 14:38:55 +01:00
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
};
|
|
|
|
|
2013-01-07 19:20:47 +01:00
|
|
|
static const char *ext4_feature_name[] = {
|
|
|
|
NULL, NULL, "xstore", "xstore-en",
|
|
|
|
NULL, NULL, "xcrypt", "xcrypt-en",
|
|
|
|
"ace2", "ace2-en", "phe", "phe-en",
|
|
|
|
"pmm", "pmm-en", NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
};
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
static const char *kvm_feature_name[] = {
|
2012-10-12 21:43:23 +02:00
|
|
|
"kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock",
|
2013-09-18 16:41:45 +02:00
|
|
|
"kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", "kvm_pv_unhalt",
|
2012-10-12 21:43:23 +02:00
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
2014-07-04 21:44:34 +02:00
|
|
|
"kvmclock-stable-bit", NULL, NULL, NULL,
|
2012-10-12 21:43:23 +02:00
|
|
|
NULL, NULL, NULL, NULL,
|
2010-03-11 14:38:55 +01:00
|
|
|
};
|
|
|
|
|
2010-09-27 15:16:17 +02:00
|
|
|
static const char *svm_feature_name[] = {
|
|
|
|
"npt", "lbrv", "svm_lock", "nrip_save",
|
|
|
|
"tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists",
|
|
|
|
NULL, NULL, "pause_filter", NULL,
|
|
|
|
"pfthreshold", NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
};
|
|
|
|
|
2012-09-26 22:18:43 +02:00
|
|
|
static const char *cpuid_7_0_ebx_feature_name[] = {
|
2014-08-25 22:02:13 +02:00
|
|
|
"fsgsbase", "tsc_adjust", NULL, "bmi1", "hle", "avx2", NULL, "smep",
|
2014-08-25 22:02:12 +02:00
|
|
|
"bmi2", "erms", "invpcid", "rtm", NULL, NULL, "mpx", NULL,
|
2014-10-23 05:02:43 +02:00
|
|
|
"avx512f", NULL, "rdseed", "adx", "smap", NULL, NULL, NULL,
|
|
|
|
NULL, NULL, "avx512pf", "avx512er", "avx512cd", NULL, NULL, NULL,
|
2012-09-26 22:18:43 +02:00
|
|
|
};
|
|
|
|
|
2014-04-30 18:48:45 +02:00
|
|
|
static const char *cpuid_apm_edx_feature_name[] = {
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
"invtsc", NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
};
|
|
|
|
|
2014-11-24 15:54:43 +01:00
|
|
|
static const char *cpuid_xsave_feature_name[] = {
|
|
|
|
"xsaveopt", "xsavec", "xgetbv1", "xsaves",
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
};
|
|
|
|
|
2014-04-30 18:48:36 +02:00
|
|
|
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
|
|
|
|
#define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
|
|
|
|
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC)
|
|
|
|
#define PENTIUM2_FEATURES (PENTIUM_FEATURES | CPUID_PAE | CPUID_SEP | \
|
|
|
|
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
|
|
|
|
CPUID_PSE36 | CPUID_FXSR)
|
|
|
|
#define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE)
|
|
|
|
#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
|
|
|
|
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
|
|
|
|
CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
|
|
|
|
CPUID_PAE | CPUID_SEP | CPUID_APIC)
|
|
|
|
|
|
|
|
#define TCG_FEATURES (CPUID_FP87 | CPUID_PSE | CPUID_TSC | CPUID_MSR | \
|
|
|
|
CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
|
|
|
|
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
|
|
|
|
CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
|
|
|
|
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS)
|
|
|
|
/* partly implemented:
|
|
|
|
CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) */
|
|
|
|
/* missing:
|
|
|
|
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
|
|
|
#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_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 */
|
|
|
|
|
|
|
|
#ifdef TARGET_X86_64
|
|
|
|
#define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM)
|
|
|
|
#else
|
|
|
|
#define TCG_EXT2_X86_64_FEATURES 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#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 | CPUID_EXT2_PDPE1GB | \
|
|
|
|
TCG_EXT2_X86_64_FEATURES)
|
|
|
|
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
|
|
|
|
CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
|
|
|
|
#define TCG_EXT4_FEATURES 0
|
|
|
|
#define TCG_SVM_FEATURES 0
|
|
|
|
#define TCG_KVM_FEATURES 0
|
|
|
|
#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 */
|
2014-04-30 18:48:45 +02:00
|
|
|
#define TCG_APM_FEATURES 0
|
2014-04-30 18:48:36 +02:00
|
|
|
|
|
|
|
|
2013-01-07 19:20:45 +01:00
|
|
|
typedef struct FeatureWordInfo {
|
|
|
|
const char **feat_names;
|
2013-04-22 21:00:16 +02:00
|
|
|
uint32_t cpuid_eax; /* Input EAX for CPUID */
|
|
|
|
bool cpuid_needs_ecx; /* CPUID instruction uses ECX as input */
|
|
|
|
uint32_t cpuid_ecx; /* Input ECX value for CPUID */
|
|
|
|
int cpuid_reg; /* output register (R_* constant) */
|
2014-04-30 18:48:38 +02:00
|
|
|
uint32_t tcg_features; /* Feature flags supported by TCG */
|
2014-04-30 18:48:41 +02:00
|
|
|
uint32_t unmigratable_flags; /* Feature flags known to be unmigratable */
|
2013-01-07 19:20:45 +01:00
|
|
|
} FeatureWordInfo;
|
|
|
|
|
|
|
|
static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
2013-01-07 19:20:46 +01:00
|
|
|
[FEAT_1_EDX] = {
|
|
|
|
.feat_names = feature_name,
|
|
|
|
.cpuid_eax = 1, .cpuid_reg = R_EDX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_FEATURES,
|
2013-01-07 19:20:46 +01:00
|
|
|
},
|
|
|
|
[FEAT_1_ECX] = {
|
|
|
|
.feat_names = ext_feature_name,
|
|
|
|
.cpuid_eax = 1, .cpuid_reg = R_ECX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_EXT_FEATURES,
|
2013-01-07 19:20:46 +01:00
|
|
|
},
|
|
|
|
[FEAT_8000_0001_EDX] = {
|
|
|
|
.feat_names = ext2_feature_name,
|
|
|
|
.cpuid_eax = 0x80000001, .cpuid_reg = R_EDX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_EXT2_FEATURES,
|
2013-01-07 19:20:46 +01:00
|
|
|
},
|
|
|
|
[FEAT_8000_0001_ECX] = {
|
|
|
|
.feat_names = ext3_feature_name,
|
|
|
|
.cpuid_eax = 0x80000001, .cpuid_reg = R_ECX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_EXT3_FEATURES,
|
2013-01-07 19:20:46 +01:00
|
|
|
},
|
2013-01-07 19:20:47 +01:00
|
|
|
[FEAT_C000_0001_EDX] = {
|
|
|
|
.feat_names = ext4_feature_name,
|
|
|
|
.cpuid_eax = 0xC0000001, .cpuid_reg = R_EDX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_EXT4_FEATURES,
|
2013-01-07 19:20:47 +01:00
|
|
|
},
|
2013-01-07 19:20:46 +01:00
|
|
|
[FEAT_KVM] = {
|
|
|
|
.feat_names = kvm_feature_name,
|
|
|
|
.cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_KVM_FEATURES,
|
2013-01-07 19:20:46 +01:00
|
|
|
},
|
|
|
|
[FEAT_SVM] = {
|
|
|
|
.feat_names = svm_feature_name,
|
|
|
|
.cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_SVM_FEATURES,
|
2013-01-07 19:20:46 +01:00
|
|
|
},
|
|
|
|
[FEAT_7_0_EBX] = {
|
|
|
|
.feat_names = cpuid_7_0_ebx_feature_name,
|
2013-04-22 21:00:16 +02:00
|
|
|
.cpuid_eax = 7,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 0,
|
|
|
|
.cpuid_reg = R_EBX,
|
2014-04-30 18:48:38 +02:00
|
|
|
.tcg_features = TCG_7_0_EBX_FEATURES,
|
2013-01-07 19:20:46 +01:00
|
|
|
},
|
2014-04-30 18:48:45 +02:00
|
|
|
[FEAT_8000_0007_EDX] = {
|
|
|
|
.feat_names = cpuid_apm_edx_feature_name,
|
|
|
|
.cpuid_eax = 0x80000007,
|
|
|
|
.cpuid_reg = R_EDX,
|
|
|
|
.tcg_features = TCG_APM_FEATURES,
|
|
|
|
.unmigratable_flags = CPUID_APM_INVTSC,
|
|
|
|
},
|
2014-11-24 15:54:43 +01:00
|
|
|
[FEAT_XSAVE] = {
|
|
|
|
.feat_names = cpuid_xsave_feature_name,
|
|
|
|
.cpuid_eax = 0xd,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 1,
|
|
|
|
.cpuid_reg = R_EAX,
|
|
|
|
.tcg_features = 0,
|
|
|
|
},
|
2013-01-07 19:20:45 +01:00
|
|
|
};
|
|
|
|
|
2013-05-06 18:20:07 +02:00
|
|
|
typedef struct X86RegisterInfo32 {
|
|
|
|
/* Name of register */
|
|
|
|
const char *name;
|
|
|
|
/* QAPI enum value register */
|
|
|
|
X86CPURegister32 qapi_enum;
|
|
|
|
} X86RegisterInfo32;
|
|
|
|
|
|
|
|
#define REGISTER(reg) \
|
2014-03-05 03:44:40 +01:00
|
|
|
[R_##reg] = { .name = #reg, .qapi_enum = X86_CPU_REGISTER32_##reg }
|
2014-03-16 15:03:41 +01:00
|
|
|
static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
|
2013-05-06 18:20:07 +02:00
|
|
|
REGISTER(EAX),
|
|
|
|
REGISTER(ECX),
|
|
|
|
REGISTER(EDX),
|
|
|
|
REGISTER(EBX),
|
|
|
|
REGISTER(ESP),
|
|
|
|
REGISTER(EBP),
|
|
|
|
REGISTER(ESI),
|
|
|
|
REGISTER(EDI),
|
|
|
|
};
|
|
|
|
#undef REGISTER
|
|
|
|
|
2013-10-02 17:54:57 +02:00
|
|
|
typedef struct ExtSaveArea {
|
|
|
|
uint32_t feature, bits;
|
|
|
|
uint32_t offset, size;
|
|
|
|
} ExtSaveArea;
|
|
|
|
|
|
|
|
static const ExtSaveArea ext_save_areas[] = {
|
|
|
|
[2] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
|
2013-12-02 21:17:50 +01:00
|
|
|
.offset = 0x240, .size = 0x100 },
|
2013-12-05 01:32:12 +01:00
|
|
|
[3] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
|
|
|
|
.offset = 0x3c0, .size = 0x40 },
|
|
|
|
[4] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
|
2014-03-03 06:24:14 +01:00
|
|
|
.offset = 0x400, .size = 0x40 },
|
2014-10-23 05:02:43 +02:00
|
|
|
[5] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
|
|
|
.offset = 0x440, .size = 0x40 },
|
|
|
|
[6] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
|
|
|
.offset = 0x480, .size = 0x200 },
|
|
|
|
[7] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
|
|
|
.offset = 0x680, .size = 0x400 },
|
2013-10-02 17:54:57 +02:00
|
|
|
};
|
2013-05-06 18:20:07 +02:00
|
|
|
|
2013-01-04 23:01:06 +01:00
|
|
|
const char *get_register_name_32(unsigned int reg)
|
|
|
|
{
|
2013-06-03 18:23:27 +02:00
|
|
|
if (reg >= CPU_NB_REGS32) {
|
2013-01-04 23:01:06 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-05-06 18:20:07 +02:00
|
|
|
return x86_reg_info_32[reg].name;
|
2013-01-04 23:01:06 +01:00
|
|
|
}
|
|
|
|
|
2014-02-19 15:58:10 +01:00
|
|
|
/* KVM-specific features that are automatically added to all CPU models
|
|
|
|
* when KVM is enabled.
|
|
|
|
*/
|
|
|
|
static uint32_t kvm_default_features[FEATURE_WORDS] = {
|
|
|
|
[FEAT_KVM] = (1 << KVM_FEATURE_CLOCKSOURCE) |
|
2012-10-18 00:15:48 +02:00
|
|
|
(1 << KVM_FEATURE_NOP_IO_DELAY) |
|
|
|
|
(1 << KVM_FEATURE_CLOCKSOURCE2) |
|
|
|
|
(1 << KVM_FEATURE_ASYNC_PF) |
|
|
|
|
(1 << KVM_FEATURE_STEAL_TIME) |
|
2013-01-17 21:59:29 +01:00
|
|
|
(1 << KVM_FEATURE_PV_EOI) |
|
2014-02-19 15:58:10 +01:00
|
|
|
(1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT),
|
2014-02-19 15:58:12 +01:00
|
|
|
[FEAT_1_ECX] = CPUID_EXT_X2APIC,
|
2014-02-19 15:58:10 +01:00
|
|
|
};
|
2012-10-18 00:15:48 +02:00
|
|
|
|
2014-04-30 18:48:28 +02:00
|
|
|
/* Features that are not added by default to any CPU model when KVM is enabled.
|
|
|
|
*/
|
|
|
|
static uint32_t kvm_default_unset_features[FEATURE_WORDS] = {
|
2014-10-03 21:39:48 +02:00
|
|
|
[FEAT_1_EDX] = CPUID_ACPI,
|
2014-04-30 18:48:28 +02:00
|
|
|
[FEAT_1_ECX] = CPUID_EXT_MONITOR,
|
2014-10-03 21:39:51 +02:00
|
|
|
[FEAT_8000_0001_ECX] = CPUID_EXT3_SVM,
|
2014-04-30 18:48:28 +02:00
|
|
|
};
|
|
|
|
|
2014-10-03 21:39:47 +02:00
|
|
|
void x86_cpu_compat_kvm_no_autoenable(FeatureWord w, uint32_t features)
|
2012-10-18 00:15:48 +02:00
|
|
|
{
|
2014-02-19 15:58:11 +01:00
|
|
|
kvm_default_features[w] &= ~features;
|
2012-10-18 00:15:48 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 21:39:51 +02:00
|
|
|
void x86_cpu_compat_kvm_no_autodisable(FeatureWord w, uint32_t features)
|
|
|
|
{
|
|
|
|
kvm_default_unset_features[w] &= ~features;
|
|
|
|
}
|
|
|
|
|
2014-04-30 18:48:41 +02:00
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
|
|
|
uint32_t r = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
uint32_t f = 1U << i;
|
|
|
|
/* If the feature name is unknown, it is not supported by QEMU yet */
|
|
|
|
if (!wi->feat_names[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Skip features known to QEMU, but explicitly marked as unmigratable */
|
|
|
|
if (wi->unmigratable_flags & f) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
r |= f;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-01-21 21:48:07 +01:00
|
|
|
void host_cpuid(uint32_t function, uint32_t count,
|
|
|
|
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
|
2010-03-11 14:38:58 +01:00
|
|
|
{
|
2011-11-27 18:13:01 +01:00
|
|
|
uint32_t vec[4];
|
|
|
|
|
|
|
|
#ifdef __x86_64__
|
|
|
|
asm volatile("cpuid"
|
|
|
|
: "=a"(vec[0]), "=b"(vec[1]),
|
|
|
|
"=c"(vec[2]), "=d"(vec[3])
|
|
|
|
: "0"(function), "c"(count) : "cc");
|
2014-01-30 20:48:53 +01:00
|
|
|
#elif defined(__i386__)
|
2011-11-27 18:13:01 +01:00
|
|
|
asm volatile("pusha \n\t"
|
|
|
|
"cpuid \n\t"
|
|
|
|
"mov %%eax, 0(%2) \n\t"
|
|
|
|
"mov %%ebx, 4(%2) \n\t"
|
|
|
|
"mov %%ecx, 8(%2) \n\t"
|
|
|
|
"mov %%edx, 12(%2) \n\t"
|
|
|
|
"popa"
|
|
|
|
: : "a"(function), "c"(count), "S"(vec)
|
|
|
|
: "memory", "cc");
|
2014-01-30 20:48:53 +01:00
|
|
|
#else
|
|
|
|
abort();
|
2011-11-27 18:13:01 +01:00
|
|
|
#endif
|
|
|
|
|
2010-03-11 14:38:58 +01:00
|
|
|
if (eax)
|
2011-11-27 18:13:01 +01:00
|
|
|
*eax = vec[0];
|
2010-03-11 14:38:58 +01:00
|
|
|
if (ebx)
|
2011-11-27 18:13:01 +01:00
|
|
|
*ebx = vec[1];
|
2010-03-11 14:38:58 +01:00
|
|
|
if (ecx)
|
2011-11-27 18:13:01 +01:00
|
|
|
*ecx = vec[2];
|
2010-03-11 14:38:58 +01:00
|
|
|
if (edx)
|
2011-11-27 18:13:01 +01:00
|
|
|
*edx = vec[3];
|
2010-03-11 14:38:58 +01:00
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
|
|
|
|
#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
|
|
|
|
|
|
|
|
/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of
|
|
|
|
* a substring. ex if !NULL points to the first char after a substring,
|
|
|
|
* otherwise the string is assumed to sized by a terminating nul.
|
|
|
|
* Return lexical ordering of *s1:*s2.
|
|
|
|
*/
|
2014-11-05 09:40:33 +01:00
|
|
|
static int sstrcmp(const char *s1, const char *e1,
|
|
|
|
const char *s2, const char *e2)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
if (!*s1 || !*s2 || *s1 != *s2)
|
|
|
|
return (*s1 - *s2);
|
|
|
|
++s1, ++s2;
|
|
|
|
if (s1 == e1 && s2 == e2)
|
|
|
|
return (0);
|
|
|
|
else if (s1 == e1)
|
|
|
|
return (*s2);
|
|
|
|
else if (s2 == e2)
|
|
|
|
return (*s1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple
|
|
|
|
* '|' delimited (possibly empty) strings in which case search for a match
|
|
|
|
* within the alternatives proceeds left to right. Return 0 for success,
|
|
|
|
* non-zero otherwise.
|
|
|
|
*/
|
|
|
|
static int altcmp(const char *s, const char *e, const char *altstr)
|
|
|
|
{
|
|
|
|
const char *p, *q;
|
|
|
|
|
|
|
|
for (q = p = altstr; ; ) {
|
|
|
|
while (*p && *p != '|')
|
|
|
|
++p;
|
|
|
|
if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
|
|
|
|
return (0);
|
|
|
|
if (!*p)
|
|
|
|
return (1);
|
|
|
|
else
|
|
|
|
q = ++p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* search featureset for flag *[s..e), if found set corresponding bit in
|
2011-04-19 13:06:06 +02:00
|
|
|
* *pval and return true, otherwise return false
|
2010-03-11 14:38:55 +01:00
|
|
|
*/
|
2011-04-19 13:06:06 +02:00
|
|
|
static bool lookup_feature(uint32_t *pval, const char *s, const char *e,
|
|
|
|
const char **featureset)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
|
|
|
uint32_t mask;
|
|
|
|
const char **ppc;
|
2011-04-19 13:06:06 +02:00
|
|
|
bool found = false;
|
2010-03-11 14:38:55 +01:00
|
|
|
|
2011-04-19 13:06:06 +02:00
|
|
|
for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) {
|
2010-03-11 14:38:55 +01:00
|
|
|
if (*ppc && !altcmp(s, e, *ppc)) {
|
|
|
|
*pval |= mask;
|
2011-04-19 13:06:06 +02:00
|
|
|
found = true;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
2011-04-19 13:06:06 +02:00
|
|
|
}
|
|
|
|
return found;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
|
2013-01-07 19:20:45 +01:00
|
|
|
static void add_flagname_to_bitmaps(const char *flagname,
|
2014-08-21 22:22:56 +02:00
|
|
|
FeatureWordArray words,
|
|
|
|
Error **errp)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
2013-01-07 19:20:45 +01:00
|
|
|
FeatureWord w;
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
|
|
|
if (wi->feat_names &&
|
|
|
|
lookup_feature(&words[w], flagname, NULL, wi->feat_names)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (w == FEATURE_WORDS) {
|
2014-08-21 22:22:56 +02:00
|
|
|
error_setg(errp, "CPU feature %s not found", flagname);
|
2013-01-07 19:20:45 +01:00
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
/* CPU class name definitions: */
|
|
|
|
|
|
|
|
#define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU
|
|
|
|
#define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
|
|
|
|
|
|
|
|
/* Return type name for a given CPU model name
|
|
|
|
* Caller is responsible for freeing the returned string.
|
|
|
|
*/
|
|
|
|
static char *x86_cpu_type_name(const char *model_name)
|
|
|
|
{
|
|
|
|
return g_strdup_printf(X86_CPU_TYPE_NAME("%s"), model_name);
|
|
|
|
}
|
|
|
|
|
2014-02-10 22:02:44 +01:00
|
|
|
static ObjectClass *x86_cpu_class_by_name(const char *cpu_model)
|
|
|
|
{
|
2014-02-10 11:21:30 +01:00
|
|
|
ObjectClass *oc;
|
|
|
|
char *typename;
|
|
|
|
|
2014-02-10 22:02:44 +01:00
|
|
|
if (cpu_model == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
typename = x86_cpu_type_name(cpu_model);
|
|
|
|
oc = object_class_by_name(typename);
|
|
|
|
g_free(typename);
|
|
|
|
return oc;
|
2014-02-10 22:02:44 +01:00
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
struct X86CPUDefinition {
|
2010-03-11 14:38:55 +01:00
|
|
|
const char *name;
|
|
|
|
uint32_t level;
|
2013-04-22 21:00:12 +02:00
|
|
|
uint32_t xlevel;
|
|
|
|
uint32_t xlevel2;
|
2013-01-21 15:06:36 +01:00
|
|
|
/* vendor is zero-terminated, 12 character ASCII string */
|
|
|
|
char vendor[CPUID_VENDOR_SZ + 1];
|
2010-03-11 14:38:55 +01:00
|
|
|
int family;
|
|
|
|
int model;
|
|
|
|
int stepping;
|
2013-04-22 21:00:15 +02:00
|
|
|
FeatureWordArray features;
|
2010-03-11 14:38:55 +01:00
|
|
|
char model_id[48];
|
2013-09-02 17:06:37 +02:00
|
|
|
bool cache_info_passthrough;
|
2014-02-10 11:21:30 +01:00
|
|
|
};
|
2010-03-11 14:38:55 +01:00
|
|
|
|
2014-01-30 20:48:58 +01:00
|
|
|
static X86CPUDefinition builtin_x86_defs[] = {
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
|
|
|
.name = "qemu64",
|
|
|
|
.level = 4,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
2013-09-10 22:48:59 +02:00
|
|
|
.model = 6,
|
2010-03-11 14:38:55 +01:00
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
|
|
|
CPUID_PSE36,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
|
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "phenom",
|
|
|
|
.level = 5,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 16,
|
|
|
|
.model = 2,
|
|
|
|
.stepping = 3,
|
2014-10-03 21:39:49 +02:00
|
|
|
/* Missing: CPUID_HT */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
2014-10-03 21:39:49 +02:00
|
|
|
CPUID_PSE36 | CPUID_VME,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_EXT_POPCNT,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
|
2010-03-13 16:43:15 +01:00
|
|
|
CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
|
2010-03-11 14:38:55 +01:00
|
|
|
/* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
|
|
|
|
CPUID_EXT3_CR8LEG,
|
|
|
|
CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
|
|
|
|
CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
|
2014-10-03 21:39:49 +02:00
|
|
|
/* Missing: CPUID_SVM_LBRV */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_SVM] =
|
2014-10-03 21:39:49 +02:00
|
|
|
CPUID_SVM_NPT,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0x8000001A,
|
|
|
|
.model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "core2duo",
|
|
|
|
.level = 10,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
|
|
|
.model = 15,
|
|
|
|
.stepping = 11,
|
2014-10-03 21:39:49 +02:00
|
|
|
/* Missing: CPUID_DTS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
2014-10-03 21:39:49 +02:00
|
|
|
CPUID_PSE36 | CPUID_VME | CPUID_ACPI | CPUID_SS,
|
|
|
|
/* Missing: CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_EST,
|
2014-10-03 21:39:50 +02:00
|
|
|
* CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_VMX */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
|
2014-10-03 21:39:50 +02:00
|
|
|
CPUID_EXT_CX16,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "kvm64",
|
|
|
|
.level = 5,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2014-12-10 17:12:41 +01:00
|
|
|
/* Missing: CPUID_HT */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
PPRO_FEATURES | CPUID_VME |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
|
|
|
CPUID_PSE36,
|
|
|
|
/* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_CX16,
|
2010-03-11 14:38:55 +01:00
|
|
|
/* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
|
2010-03-11 14:38:55 +01:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
|
|
|
/* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
|
|
|
|
CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
|
|
|
|
CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
|
|
|
|
CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
0,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Common KVM processor"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "qemu32",
|
|
|
|
.level = 4,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
2013-09-10 22:48:59 +02:00
|
|
|
.model = 6,
|
2010-03-11 14:38:55 +01:00
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
|
2010-03-11 14:39:06 +01:00
|
|
|
.xlevel = 0x80000004,
|
2010-03-11 14:38:55 +01:00
|
|
|
},
|
2010-05-21 09:50:51 +02:00
|
|
|
{
|
|
|
|
.name = "kvm32",
|
|
|
|
.level = 5,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-05-21 09:50:51 +02:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
PPRO_FEATURES | CPUID_VME |
|
2010-05-21 09:50:51 +02:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
0,
|
2010-05-21 09:50:51 +02:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Common 32-bit KVM processor"
|
|
|
|
},
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
|
|
|
.name = "coreduo",
|
|
|
|
.level = 10,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
|
|
|
.model = 14,
|
|
|
|
.stepping = 8,
|
2014-10-03 21:39:49 +02:00
|
|
|
/* Missing: CPUID_DTS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES | CPUID_VME |
|
2014-10-03 21:39:49 +02:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_ACPI |
|
|
|
|
CPUID_SS,
|
|
|
|
/* Missing: CPUID_EXT_EST, CPUID_EXT_TM2 , CPUID_EXT_XTPR,
|
2014-10-03 21:39:50 +02:00
|
|
|
* CPUID_EXT_PDCM, CPUID_EXT_VMX */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2014-10-03 21:39:50 +02:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_NX,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "486",
|
2010-03-11 14:39:06 +01:00
|
|
|
.level = 1,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 4,
|
2013-05-01 17:30:51 +02:00
|
|
|
.model = 8,
|
2010-03-11 14:38:55 +01:00
|
|
|
.stepping = 0,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
I486_FEATURES,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "pentium",
|
|
|
|
.level = 1,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 5,
|
|
|
|
.model = 4,
|
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PENTIUM_FEATURES,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "pentium2",
|
|
|
|
.level = 2,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
|
|
|
.model = 5,
|
|
|
|
.stepping = 2,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PENTIUM2_FEATURES,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "pentium3",
|
|
|
|
.level = 2,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
|
|
|
.model = 7,
|
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PENTIUM3_FEATURES,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "athlon",
|
|
|
|
.level = 2,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
|
|
|
.model = 2,
|
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR |
|
2012-09-06 12:05:37 +02:00
|
|
|
CPUID_MCA,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
|
2012-09-06 12:05:37 +02:00
|
|
|
CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "n270",
|
|
|
|
/* original is on level 10 */
|
|
|
|
.level = 5,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 14:38:55 +01:00
|
|
|
.family = 6,
|
|
|
|
.model = 28,
|
|
|
|
.stepping = 2,
|
2014-10-03 21:39:49 +02:00
|
|
|
/* Missing: CPUID_DTS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
PPRO_FEATURES |
|
2014-10-03 21:39:49 +02:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME |
|
|
|
|
CPUID_ACPI | CPUID_SS,
|
2010-03-11 14:38:55 +01:00
|
|
|
/* Some CPUs got no CPUID_SEP */
|
2014-10-03 21:39:49 +02:00
|
|
|
/* Missing: CPUID_EXT_DSCPL, CPUID_EXT_EST, CPUID_EXT_TM2,
|
|
|
|
* CPUID_EXT_XTPR */
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
|
2013-04-25 20:43:04 +02:00
|
|
|
CPUID_EXT_MOVBE,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
|
2012-09-06 12:05:37 +02:00
|
|
|
CPUID_EXT2_NX,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2010-03-11 14:38:55 +01:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz",
|
|
|
|
},
|
2012-09-05 22:41:10 +02:00
|
|
|
{
|
|
|
|
.name = "Conroe",
|
2013-05-27 22:23:55 +02:00
|
|
|
.level = 4,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 6,
|
2013-05-27 22:23:54 +02:00
|
|
|
.model = 15,
|
2012-09-05 22:41:10 +02:00
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Penryn",
|
2013-05-27 22:23:55 +02:00
|
|
|
.level = 4,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 6,
|
2013-05-27 22:23:54 +02:00
|
|
|
.model = 23,
|
2012-09-05 22:41:10 +02:00
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Nehalem",
|
2013-05-27 22:23:55 +02:00
|
|
|
.level = 4,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 6,
|
2013-05-27 22:23:54 +02:00
|
|
|
.model = 26,
|
2012-09-05 22:41:10 +02:00
|
|
|
.stepping = 3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel Core i7 9xx (Nehalem Class Core i7)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Westmere",
|
|
|
|
.level = 11,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 6,
|
|
|
|
.model = 44,
|
|
|
|
.stepping = 1,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
|
|
|
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SandyBridge",
|
|
|
|
.level = 0xd,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 6,
|
|
|
|
.model = 42,
|
|
|
|
.stepping = 1,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
|
|
|
|
CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
|
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT2_SYSCALL,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2014-11-24 15:54:43 +01:00
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel Xeon E312xx (Sandy Bridge)",
|
|
|
|
},
|
2014-12-05 10:55:23 +01:00
|
|
|
{
|
|
|
|
.name = "IvyBridge",
|
|
|
|
.level = 0xd,
|
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
|
|
|
.family = 6,
|
|
|
|
.model = 58,
|
|
|
|
.stepping = 9,
|
|
|
|
.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_TSC_DEADLINE_TIMER | 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_F16C | CPUID_EXT_RDRAND,
|
|
|
|
.features[FEAT_7_0_EBX] =
|
|
|
|
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_SMEP |
|
|
|
|
CPUID_7_0_EBX_ERMS,
|
|
|
|
.features[FEAT_8000_0001_EDX] =
|
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
|
|
|
.features[FEAT_8000_0001_ECX] =
|
|
|
|
CPUID_EXT3_LAHF_LM,
|
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge)",
|
|
|
|
},
|
target-i386: Add Haswell CPU model
Features added to the model, in relation to SandyBridge:
fma CPUID[1].ECX[12]
pcid CPUID[1].ECX[17]
movbe CPUID[1].ECX[22]
fsgsbase CPUID[EAX=7,ECX=0].EBX[0]
bmi1 CPUID[EAX=7,ECX=0].EBX[3]
hle CPUID[EAX=7,ECX=0].EBX[4]
avx2 CPUID[EAX=7,ECX=0].EBX[5]
smep CPUID[EAX=7,ECX=0].EBX[7]
bmi2 CPUID[EAX=7,ECX=0].EBX[8]
erms CPUID[EAX=7,ECX=0].EBX[9]
invpcid CPUID[EAX=7,ECX=0].EBX[10]
rtm CPUID[EAX=7,ECX=0].EBX[11]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 19:28:54 +01:00
|
|
|
{
|
|
|
|
.name = "Haswell",
|
|
|
|
.level = 0xd,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
target-i386: Add Haswell CPU model
Features added to the model, in relation to SandyBridge:
fma CPUID[1].ECX[12]
pcid CPUID[1].ECX[17]
movbe CPUID[1].ECX[22]
fsgsbase CPUID[EAX=7,ECX=0].EBX[0]
bmi1 CPUID[EAX=7,ECX=0].EBX[3]
hle CPUID[EAX=7,ECX=0].EBX[4]
avx2 CPUID[EAX=7,ECX=0].EBX[5]
smep CPUID[EAX=7,ECX=0].EBX[7]
bmi2 CPUID[EAX=7,ECX=0].EBX[8]
erms CPUID[EAX=7,ECX=0].EBX[9]
invpcid CPUID[EAX=7,ECX=0].EBX[10]
rtm CPUID[EAX=7,ECX=0].EBX[11]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 19:28:54 +01:00
|
|
|
.family = 6,
|
|
|
|
.model = 60,
|
|
|
|
.stepping = 1,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
2014-06-18 01:05:29 +02:00
|
|
|
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 |
|
2014-12-05 10:52:46 +01:00
|
|
|
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT2_SYSCALL,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_7_0_EBX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
2015-01-22 20:22:54 +01:00
|
|
|
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,
|
2014-11-24 15:54:43 +01:00
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
target-i386: Add Haswell CPU model
Features added to the model, in relation to SandyBridge:
fma CPUID[1].ECX[12]
pcid CPUID[1].ECX[17]
movbe CPUID[1].ECX[22]
fsgsbase CPUID[EAX=7,ECX=0].EBX[0]
bmi1 CPUID[EAX=7,ECX=0].EBX[3]
hle CPUID[EAX=7,ECX=0].EBX[4]
avx2 CPUID[EAX=7,ECX=0].EBX[5]
smep CPUID[EAX=7,ECX=0].EBX[7]
bmi2 CPUID[EAX=7,ECX=0].EBX[8]
erms CPUID[EAX=7,ECX=0].EBX[9]
invpcid CPUID[EAX=7,ECX=0].EBX[10]
rtm CPUID[EAX=7,ECX=0].EBX[11]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 19:28:54 +01:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel Core Processor (Haswell)",
|
|
|
|
},
|
2014-06-17 22:11:40 +02:00
|
|
|
{
|
|
|
|
.name = "Broadwell",
|
|
|
|
.level = 0xd,
|
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
|
|
|
.family = 6,
|
|
|
|
.model = 61,
|
|
|
|
.stepping = 2,
|
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-17 22:11:40 +02:00
|
|
|
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 |
|
2014-12-05 10:52:46 +01:00
|
|
|
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
2014-06-17 22:11:40 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
|
|
|
.features[FEAT_8000_0001_ECX] =
|
|
|
|
CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
|
|
|
.features[FEAT_7_0_EBX] =
|
|
|
|
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
2015-01-22 20:22:54 +01:00
|
|
|
CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
2014-06-17 22:11:40 +02:00
|
|
|
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
2015-01-22 20:22:54 +01:00
|
|
|
CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
2014-06-17 22:11:40 +02:00
|
|
|
CPUID_7_0_EBX_SMAP,
|
2014-11-24 15:54:43 +01:00
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2014-06-17 22:11:40 +02:00
|
|
|
.xlevel = 0x8000000A,
|
|
|
|
.model_id = "Intel Core Processor (Broadwell)",
|
|
|
|
},
|
2012-09-05 22:41:10 +02:00
|
|
|
{
|
|
|
|
.name = "Opteron_G1",
|
|
|
|
.level = 5,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
|
|
|
|
CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
|
|
|
|
CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
|
|
|
|
CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
|
|
|
|
CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "AMD Opteron 240 (Gen 1 Class Opteron)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Opteron_G2",
|
|
|
|
.level = 5,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PSE36 |
|
|
|
|
CPUID_EXT2_PAT | CPUID_EXT2_CMOV | CPUID_EXT2_MCA |
|
|
|
|
CPUID_EXT2_PGE | CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL |
|
|
|
|
CPUID_EXT2_APIC | CPUID_EXT2_CX8 | CPUID_EXT2_MCE |
|
|
|
|
CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | CPUID_EXT2_PSE |
|
|
|
|
CPUID_EXT2_DE | CPUID_EXT2_FPU,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Opteron_G3",
|
|
|
|
.level = 5,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_CX16 | CPUID_EXT_MONITOR |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PSE36 |
|
|
|
|
CPUID_EXT2_PAT | CPUID_EXT2_CMOV | CPUID_EXT2_MCA |
|
|
|
|
CPUID_EXT2_PGE | CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL |
|
|
|
|
CPUID_EXT2_APIC | CPUID_EXT2_CX8 | CPUID_EXT2_MCE |
|
|
|
|
CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | CPUID_EXT2_PSE |
|
|
|
|
CPUID_EXT2_DE | CPUID_EXT2_FPU,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Opteron_G4",
|
|
|
|
.level = 0xd,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-09-05 22:41:10 +02:00
|
|
|
.family = 21,
|
|
|
|
.model = 1,
|
|
|
|
.stepping = 2,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
|
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
|
|
|
|
CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
|
|
|
|
CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
|
|
|
|
CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
|
|
|
|
CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
|
|
|
|
CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
|
|
|
|
CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
|
|
|
|
CPUID_EXT3_LAHF_LM,
|
2014-11-24 15:54:43 +01:00
|
|
|
/* no xsaveopt! */
|
2012-09-05 22:41:10 +02:00
|
|
|
.xlevel = 0x8000001A,
|
|
|
|
.model_id = "AMD Opteron 62xx class CPU",
|
|
|
|
},
|
2012-11-14 19:28:53 +01:00
|
|
|
{
|
|
|
|
.name = "Opteron_G5",
|
|
|
|
.level = 0xd,
|
2013-01-21 15:06:36 +01:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-11-14 19:28:53 +01:00
|
|
|
.family = 21,
|
|
|
|
.model = 2,
|
|
|
|
.stepping = 0,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 17:12:41 +01:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 01:05:29 +02:00
|
|
|
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,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT_F16C | CPUID_EXT_AVX | CPUID_EXT_XSAVE |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_FMA |
|
|
|
|
CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
|
|
|
|
CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
|
|
|
|
CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
|
|
|
|
CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
|
|
|
|
CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
|
|
|
|
CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
|
2013-04-22 21:00:15 +02:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 21:00:14 +02:00
|
|
|
CPUID_EXT3_TBM | CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
|
2014-06-18 01:05:29 +02:00
|
|
|
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
|
|
|
|
CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
|
|
|
|
CPUID_EXT3_LAHF_LM,
|
2014-11-24 15:54:43 +01:00
|
|
|
/* no xsaveopt! */
|
2012-11-14 19:28:53 +01:00
|
|
|
.xlevel = 0x8000001A,
|
|
|
|
.model_id = "AMD Opteron 63xx class CPU",
|
|
|
|
},
|
2010-03-11 14:38:55 +01:00
|
|
|
};
|
|
|
|
|
2013-04-25 20:43:00 +02:00
|
|
|
/**
|
|
|
|
* x86_cpu_compat_set_features:
|
|
|
|
* @cpu_model: CPU model name to be changed. If NULL, all CPU models are changed
|
|
|
|
* @w: Identifies the feature word to be changed.
|
|
|
|
* @feat_add: Feature bits to be added to feature word
|
|
|
|
* @feat_remove: Feature bits to be removed from feature word
|
|
|
|
*
|
|
|
|
* Change CPU model feature bits for compatibility.
|
|
|
|
*
|
|
|
|
* This function may be used by machine-type compatibility functions
|
|
|
|
* to enable or disable feature bits on specific CPU models.
|
|
|
|
*/
|
|
|
|
void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
|
|
|
|
uint32_t feat_add, uint32_t feat_remove)
|
|
|
|
{
|
2014-01-30 20:48:58 +01:00
|
|
|
X86CPUDefinition *def;
|
2013-04-25 20:43:00 +02:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
|
|
|
def = &builtin_x86_defs[i];
|
|
|
|
if (!cpu_model || !strcmp(cpu_model, def->name)) {
|
|
|
|
def->features[w] |= feat_add;
|
|
|
|
def->features[w] &= ~feat_remove;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 22:30:12 +02:00
|
|
|
static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
|
bool migratable_only);
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
static int cpu_x86_fill_model_id(char *str)
|
|
|
|
{
|
|
|
|
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
|
|
|
|
memcpy(str + i * 16 + 0, &eax, 4);
|
|
|
|
memcpy(str + i * 16 + 4, &ebx, 4);
|
|
|
|
memcpy(str + i * 16 + 8, &ecx, 4);
|
|
|
|
memcpy(str + i * 16 + 12, &edx, 4);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
static X86CPUDefinition host_cpudef;
|
|
|
|
|
2014-04-30 18:48:41 +02:00
|
|
|
static Property host_x86_cpu_properties[] = {
|
2014-06-17 22:31:53 +02:00
|
|
|
DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true),
|
2014-04-30 18:48:41 +02:00
|
|
|
DEFINE_PROP_END_OF_LIST()
|
|
|
|
};
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
/* class_init for the "host" CPU model
|
2012-10-24 23:44:06 +02:00
|
|
|
*
|
2014-02-10 11:21:30 +01:00
|
|
|
* This function may be called before KVM is initialized.
|
2012-10-24 23:44:06 +02:00
|
|
|
*/
|
2014-02-10 11:21:30 +01:00
|
|
|
static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
2014-04-30 18:48:41 +02:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
2014-02-10 11:21:30 +01:00
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
2010-03-11 14:38:55 +01:00
|
|
|
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
xcc->kvm_required = true;
|
2012-10-24 23:44:06 +02:00
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
|
2014-02-10 11:21:30 +01:00
|
|
|
x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
|
2010-03-11 14:38:55 +01:00
|
|
|
|
|
|
|
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
|
2014-02-10 11:21:30 +01:00
|
|
|
host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
|
|
|
|
host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
|
|
|
|
host_cpudef.stepping = eax & 0x0F;
|
2010-03-11 14:38:55 +01:00
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
cpu_x86_fill_model_id(host_cpudef.model_id);
|
2014-01-20 17:41:12 +01:00
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
xcc->cpu_def = &host_cpudef;
|
|
|
|
host_cpudef.cache_info_passthrough = true;
|
|
|
|
|
|
|
|
/* level, xlevel, xlevel2, and the feature words are initialized on
|
|
|
|
* instance_init, because they require KVM to be initialized.
|
|
|
|
*/
|
2014-04-30 18:48:41 +02:00
|
|
|
|
|
|
|
dc->props = host_x86_cpu_properties;
|
2014-02-10 11:21:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void host_x86_cpu_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
KVMState *s = kvm_state;
|
|
|
|
|
|
|
|
assert(kvm_enabled());
|
|
|
|
|
2014-08-20 22:30:12 +02:00
|
|
|
/* We can't fill the features array here because we don't know yet if
|
|
|
|
* "migratable" is true or false.
|
|
|
|
*/
|
|
|
|
cpu->host_features = true;
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
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);
|
2014-01-20 17:41:12 +01:00
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
static const TypeInfo host_x86_cpu_type_info = {
|
|
|
|
.name = X86_CPU_TYPE_NAME("host"),
|
|
|
|
.parent = TYPE_X86_CPU,
|
|
|
|
.instance_init = host_x86_cpu_initfn,
|
|
|
|
.class_init = host_x86_cpu_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2014-04-30 18:48:31 +02:00
|
|
|
static void report_unavailable_features(FeatureWord w, uint32_t mask)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
2014-04-30 18:48:31 +02:00
|
|
|
FeatureWordInfo *f = &feature_word_info[w];
|
2010-03-11 14:38:55 +01:00
|
|
|
int i;
|
|
|
|
|
2014-04-30 18:48:29 +02:00
|
|
|
for (i = 0; i < 32; ++i) {
|
2010-03-11 14:38:55 +01:00
|
|
|
if (1 << i & mask) {
|
2013-01-07 19:20:46 +01:00
|
|
|
const char *reg = get_register_name_32(f->cpuid_reg);
|
2013-01-04 23:01:06 +01:00
|
|
|
assert(reg);
|
2014-04-30 18:48:39 +02:00
|
|
|
fprintf(stderr, "warning: %s doesn't support requested feature: "
|
2013-01-04 23:01:06 +01:00
|
|
|
"CPUID.%02XH:%s%s%s [bit %d]\n",
|
2014-04-30 18:48:39 +02:00
|
|
|
kvm_enabled() ? "host" : "TCG",
|
2013-01-07 19:20:46 +01:00
|
|
|
f->cpuid_eax, reg,
|
|
|
|
f->feat_names[i] ? "." : "",
|
|
|
|
f->feat_names[i] ? f->feat_names[i] : "", i);
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
2014-04-30 18:48:29 +02:00
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
|
2012-04-17 14:42:22 +02:00
|
|
|
static void x86_cpuid_version_get_family(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = (env->cpuid_version >> 8) & 0xf;
|
|
|
|
if (value == 0xf) {
|
|
|
|
value += (env->cpuid_version >> 20) & 0xff;
|
|
|
|
}
|
|
|
|
visit_type_int(v, &value, name, errp);
|
|
|
|
}
|
|
|
|
|
2012-04-17 12:10:29 +02:00
|
|
|
static void x86_cpuid_version_set_family(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
2012-02-17 17:46:01 +01:00
|
|
|
{
|
2012-04-17 12:10:29 +02:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
const int64_t min = 0;
|
|
|
|
const int64_t max = 0xff + 0xf;
|
2014-04-25 12:44:22 +02:00
|
|
|
Error *local_err = NULL;
|
2012-04-17 12:10:29 +02:00
|
|
|
int64_t value;
|
|
|
|
|
2014-04-25 12:44:22 +02:00
|
|
|
visit_type_int(v, &value, name, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-17 12:10:29 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
|
|
|
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-17 17:46:01 +01:00
|
|
|
env->cpuid_version &= ~0xff00f00;
|
2012-04-17 12:10:29 +02:00
|
|
|
if (value > 0x0f) {
|
|
|
|
env->cpuid_version |= 0xf00 | ((value - 0x0f) << 20);
|
2012-02-17 17:46:01 +01:00
|
|
|
} else {
|
2012-04-17 12:10:29 +02:00
|
|
|
env->cpuid_version |= value << 8;
|
2012-02-17 17:46:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-17 14:48:14 +02:00
|
|
|
static void x86_cpuid_version_get_model(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = (env->cpuid_version >> 4) & 0xf;
|
|
|
|
value |= ((env->cpuid_version >> 16) & 0xf) << 4;
|
|
|
|
visit_type_int(v, &value, name, errp);
|
|
|
|
}
|
|
|
|
|
2012-04-17 12:16:39 +02:00
|
|
|
static void x86_cpuid_version_set_model(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
2012-02-17 17:46:02 +01:00
|
|
|
{
|
2012-04-17 12:16:39 +02:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
const int64_t min = 0;
|
|
|
|
const int64_t max = 0xff;
|
2014-04-25 12:44:22 +02:00
|
|
|
Error *local_err = NULL;
|
2012-04-17 12:16:39 +02:00
|
|
|
int64_t value;
|
|
|
|
|
2014-04-25 12:44:22 +02:00
|
|
|
visit_type_int(v, &value, name, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-17 12:16:39 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
|
|
|
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-17 17:46:02 +01:00
|
|
|
env->cpuid_version &= ~0xf00f0;
|
2012-04-17 12:16:39 +02:00
|
|
|
env->cpuid_version |= ((value & 0xf) << 4) | ((value >> 4) << 16);
|
2012-02-17 17:46:02 +01:00
|
|
|
}
|
|
|
|
|
2012-04-17 14:50:53 +02:00
|
|
|
static void x86_cpuid_version_get_stepping(Object *obj, Visitor *v,
|
|
|
|
void *opaque, const char *name,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = env->cpuid_version & 0xf;
|
|
|
|
visit_type_int(v, &value, name, errp);
|
|
|
|
}
|
|
|
|
|
2012-04-17 14:14:18 +02:00
|
|
|
static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
|
|
|
|
void *opaque, const char *name,
|
|
|
|
Error **errp)
|
2012-02-17 17:46:03 +01:00
|
|
|
{
|
2012-04-17 14:14:18 +02:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
const int64_t min = 0;
|
|
|
|
const int64_t max = 0xf;
|
2014-04-25 12:44:22 +02:00
|
|
|
Error *local_err = NULL;
|
2012-04-17 14:14:18 +02:00
|
|
|
int64_t value;
|
|
|
|
|
2014-04-25 12:44:22 +02:00
|
|
|
visit_type_int(v, &value, name, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-17 14:14:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
|
|
|
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-17 17:46:03 +01:00
|
|
|
env->cpuid_version &= ~0xf;
|
2012-04-17 14:14:18 +02:00
|
|
|
env->cpuid_version |= value & 0xf;
|
2012-02-17 17:46:03 +01:00
|
|
|
}
|
|
|
|
|
2012-04-17 18:41:40 +02:00
|
|
|
static void x86_cpuid_get_level(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
|
2012-05-01 23:33:13 +02:00
|
|
|
visit_type_uint32(v, &cpu->env.cpuid_level, name, errp);
|
2012-04-17 18:41:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpuid_set_level(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
|
2012-05-01 23:33:13 +02:00
|
|
|
visit_type_uint32(v, &cpu->env.cpuid_level, name, errp);
|
2012-04-17 18:41:40 +02:00
|
|
|
}
|
|
|
|
|
2012-04-17 18:44:07 +02:00
|
|
|
static void x86_cpuid_get_xlevel(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
|
2012-05-01 23:33:13 +02:00
|
|
|
visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp);
|
2012-04-17 18:44:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpuid_set_xlevel(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
|
2012-05-01 23:33:13 +02:00
|
|
|
visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp);
|
2012-04-17 18:44:07 +02:00
|
|
|
}
|
|
|
|
|
2012-04-17 19:22:58 +02:00
|
|
|
static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
char *value;
|
|
|
|
|
2014-12-04 14:46:46 +01:00
|
|
|
value = g_malloc(CPUID_VENDOR_SZ + 1);
|
2013-01-21 15:06:36 +01:00
|
|
|
x86_cpu_vendor_words2str(value, env->cpuid_vendor1, env->cpuid_vendor2,
|
|
|
|
env->cpuid_vendor3);
|
2012-04-17 19:22:58 +02:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpuid_set_vendor(Object *obj, const char *value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int i;
|
|
|
|
|
2012-10-22 17:03:10 +02:00
|
|
|
if (strlen(value) != CPUID_VENDOR_SZ) {
|
2012-04-17 19:22:58 +02:00
|
|
|
error_set(errp, QERR_PROPERTY_VALUE_BAD, "",
|
|
|
|
"vendor", value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
env->cpuid_vendor1 = 0;
|
|
|
|
env->cpuid_vendor2 = 0;
|
|
|
|
env->cpuid_vendor3 = 0;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
env->cpuid_vendor1 |= ((uint8_t)value[i ]) << (8 * i);
|
|
|
|
env->cpuid_vendor2 |= ((uint8_t)value[i + 4]) << (8 * i);
|
|
|
|
env->cpuid_vendor3 |= ((uint8_t)value[i + 8]) << (8 * i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-17 23:02:26 +02:00
|
|
|
static char *x86_cpuid_get_model_id(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
char *value;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
value = g_malloc(48 + 1);
|
|
|
|
for (i = 0; i < 48; i++) {
|
|
|
|
value[i] = env->cpuid_model[i >> 2] >> (8 * (i & 3));
|
|
|
|
}
|
|
|
|
value[48] = '\0';
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2012-04-17 15:17:27 +02:00
|
|
|
static void x86_cpuid_set_model_id(Object *obj, const char *model_id,
|
|
|
|
Error **errp)
|
2012-02-17 17:46:04 +01:00
|
|
|
{
|
2012-04-17 15:17:27 +02:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
2012-02-17 17:46:04 +01:00
|
|
|
int c, len, i;
|
|
|
|
|
|
|
|
if (model_id == NULL) {
|
|
|
|
model_id = "";
|
|
|
|
}
|
|
|
|
len = strlen(model_id);
|
2012-04-17 18:21:52 +02:00
|
|
|
memset(env->cpuid_model, 0, 48);
|
2012-02-17 17:46:04 +01:00
|
|
|
for (i = 0; i < 48; i++) {
|
|
|
|
if (i >= len) {
|
|
|
|
c = '\0';
|
|
|
|
} else {
|
|
|
|
c = (uint8_t)model_id[i];
|
|
|
|
}
|
|
|
|
env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-18 00:12:23 +02:00
|
|
|
static void x86_cpuid_get_tsc_freq(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = cpu->env.tsc_khz * 1000;
|
|
|
|
visit_type_int(v, &value, name, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
const int64_t min = 0;
|
2012-09-22 02:13:13 +02:00
|
|
|
const int64_t max = INT64_MAX;
|
2014-04-25 12:44:22 +02:00
|
|
|
Error *local_err = NULL;
|
2012-04-18 00:12:23 +02:00
|
|
|
int64_t value;
|
|
|
|
|
2014-04-25 12:44:22 +02:00
|
|
|
visit_type_int(v, &value, name, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-18 00:12:23 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
|
|
|
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu->env.tsc_khz = value / 1000;
|
|
|
|
}
|
|
|
|
|
2013-04-25 16:05:26 +02:00
|
|
|
static void x86_cpuid_get_apic_id(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
int64_t value = cpu->env.cpuid_apic_id;
|
|
|
|
|
|
|
|
visit_type_int(v, &value, name, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
2013-04-26 19:51:52 +02:00
|
|
|
DeviceState *dev = DEVICE(obj);
|
2013-04-25 16:05:26 +02:00
|
|
|
const int64_t min = 0;
|
|
|
|
const int64_t max = UINT32_MAX;
|
|
|
|
Error *error = NULL;
|
|
|
|
int64_t value;
|
|
|
|
|
2013-04-26 19:51:52 +02:00
|
|
|
if (dev->realized) {
|
|
|
|
error_setg(errp, "Attempt to set property '%s' on '%s' after "
|
|
|
|
"it was realized", name, object_get_typename(obj));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-25 16:05:26 +02:00
|
|
|
visit_type_int(v, &value, name, &error);
|
|
|
|
if (error) {
|
|
|
|
error_propagate(errp, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
|
|
|
error_setg(errp, "Property %s.%s doesn't take value %" PRId64
|
|
|
|
" (minimum: %" PRId64 ", maximum: %" PRId64 ")" ,
|
|
|
|
object_get_typename(obj), name, value, min, max);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((value != cpu->env.cpuid_apic_id) && cpu_exists(value)) {
|
|
|
|
error_setg(errp, "CPU with APIC ID %" PRIi64 " exists", value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cpu->env.cpuid_apic_id = value;
|
|
|
|
}
|
|
|
|
|
2013-05-06 18:20:09 +02:00
|
|
|
/* Generic getter for "feature-words" and "filtered-features" properties */
|
2013-05-06 18:20:07 +02:00
|
|
|
static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
2013-05-06 18:20:09 +02:00
|
|
|
uint32_t *array = (uint32_t *)opaque;
|
2013-05-06 18:20:07 +02:00
|
|
|
FeatureWord w;
|
|
|
|
Error *err = NULL;
|
|
|
|
X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
|
|
|
|
X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { };
|
|
|
|
X86CPUFeatureWordInfoList *list = NULL;
|
|
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
|
|
|
X86CPUFeatureWordInfo *qwi = &word_infos[w];
|
|
|
|
qwi->cpuid_input_eax = wi->cpuid_eax;
|
|
|
|
qwi->has_cpuid_input_ecx = wi->cpuid_needs_ecx;
|
|
|
|
qwi->cpuid_input_ecx = wi->cpuid_ecx;
|
|
|
|
qwi->cpuid_register = x86_reg_info_32[wi->cpuid_reg].qapi_enum;
|
2013-05-06 18:20:09 +02:00
|
|
|
qwi->features = array[w];
|
2013-05-06 18:20:07 +02:00
|
|
|
|
|
|
|
/* List will be in reverse order, but order shouldn't matter */
|
|
|
|
list_entries[w].next = list;
|
|
|
|
list_entries[w].value = &word_infos[w];
|
|
|
|
list = &list_entries[w];
|
|
|
|
}
|
|
|
|
|
|
|
|
visit_type_X86CPUFeatureWordInfoList(v, &list, "feature-words", &err);
|
|
|
|
error_propagate(errp, err);
|
|
|
|
}
|
|
|
|
|
2013-06-04 15:05:25 +02:00
|
|
|
static void x86_get_hv_spinlocks(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
int64_t value = cpu->hyperv_spinlock_attempts;
|
|
|
|
|
|
|
|
visit_type_int(v, &value, name, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_set_hv_spinlocks(Object *obj, Visitor *v, void *opaque,
|
|
|
|
const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
const int64_t min = 0xFFF;
|
|
|
|
const int64_t max = UINT_MAX;
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
Error *err = NULL;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
visit_type_int(v, &value, name, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < min || value > max) {
|
|
|
|
error_setg(errp, "Property %s.%s doesn't take value %" PRId64
|
2014-07-28 09:13:06 +02:00
|
|
|
" (minimum: %" PRId64 ", maximum: %" PRId64 ")",
|
|
|
|
object_get_typename(obj), name ? name : "null",
|
|
|
|
value, min, max);
|
2013-06-04 15:05:25 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
cpu->hyperv_spinlock_attempts = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PropertyInfo qdev_prop_spinlocks = {
|
|
|
|
.name = "int",
|
|
|
|
.get = x86_get_hv_spinlocks,
|
|
|
|
.set = x86_set_hv_spinlocks,
|
|
|
|
};
|
|
|
|
|
2013-04-26 18:04:32 +02:00
|
|
|
/* Convert all '_' in a feature string option name to '-', to make feature
|
|
|
|
* name conform to QOM property naming rule, which uses '-' instead of '_'.
|
|
|
|
*/
|
|
|
|
static inline void feat2prop(char *s)
|
|
|
|
{
|
|
|
|
while ((s = strchr(s, '_'))) {
|
|
|
|
*s = '-';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-04 20:34:39 +01:00
|
|
|
/* Parse "+feature,-feature,feature=foo" CPU feature string
|
|
|
|
*/
|
2014-03-03 23:19:19 +01:00
|
|
|
static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
|
|
|
|
Error **errp)
|
2012-12-04 20:34:39 +01:00
|
|
|
{
|
2014-03-03 23:19:19 +01:00
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
2012-12-04 20:34:39 +01:00
|
|
|
char *featurestr; /* Single 'key=value" string being parsed */
|
2014-04-30 18:48:37 +02:00
|
|
|
FeatureWord w;
|
2012-12-04 20:34:39 +01:00
|
|
|
/* Features to be added */
|
2013-01-11 03:10:15 +01:00
|
|
|
FeatureWordArray plus_features = { 0 };
|
2012-12-04 20:34:39 +01:00
|
|
|
/* Features to be removed */
|
2013-01-07 19:20:45 +01:00
|
|
|
FeatureWordArray minus_features = { 0 };
|
2012-12-04 20:34:39 +01:00
|
|
|
uint32_t numvalue;
|
2013-01-21 15:06:38 +01:00
|
|
|
CPUX86State *env = &cpu->env;
|
2014-03-03 23:19:19 +01:00
|
|
|
Error *local_err = NULL;
|
2012-12-04 20:34:39 +01:00
|
|
|
|
|
|
|
featurestr = features ? strtok(features, ",") : NULL;
|
2010-03-11 14:38:55 +01:00
|
|
|
|
|
|
|
while (featurestr) {
|
|
|
|
char *val;
|
|
|
|
if (featurestr[0] == '+') {
|
2014-08-21 22:22:56 +02:00
|
|
|
add_flagname_to_bitmaps(featurestr + 1, plus_features, &local_err);
|
2010-03-11 14:38:55 +01:00
|
|
|
} else if (featurestr[0] == '-') {
|
2014-08-21 22:22:56 +02:00
|
|
|
add_flagname_to_bitmaps(featurestr + 1, minus_features, &local_err);
|
2010-03-11 14:38:55 +01:00
|
|
|
} else if ((val = strchr(featurestr, '='))) {
|
|
|
|
*val = 0; val++;
|
2013-04-26 18:04:32 +02:00
|
|
|
feat2prop(featurestr);
|
2012-12-14 01:29:56 +01:00
|
|
|
if (!strcmp(featurestr, "xlevel")) {
|
2010-03-11 14:38:55 +01:00
|
|
|
char *err;
|
2013-01-21 15:06:38 +01:00
|
|
|
char num[32];
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
numvalue = strtoul(val, &err, 0);
|
|
|
|
if (!*val || *err) {
|
2014-06-06 15:21:25 +02:00
|
|
|
error_setg(errp, "bad numerical value %s", val);
|
|
|
|
return;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
if (numvalue < 0x80000000) {
|
2014-03-03 23:19:19 +01:00
|
|
|
error_report("xlevel value shall always be >= 0x80000000"
|
|
|
|
", fixup will be removed in future versions");
|
2010-03-13 16:46:33 +01:00
|
|
|
numvalue += 0x80000000;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
2013-01-21 15:06:38 +01:00
|
|
|
snprintf(num, sizeof(num), "%" PRIu32, numvalue);
|
2014-03-03 23:19:19 +01:00
|
|
|
object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
|
2013-04-26 18:04:32 +02:00
|
|
|
} else if (!strcmp(featurestr, "tsc-freq")) {
|
2011-07-07 16:13:12 +02:00
|
|
|
int64_t tsc_freq;
|
|
|
|
char *err;
|
2013-01-21 15:06:38 +01:00
|
|
|
char num[32];
|
2011-07-07 16:13:12 +02:00
|
|
|
|
|
|
|
tsc_freq = strtosz_suffix_unit(val, &err,
|
|
|
|
STRTOSZ_DEFSUFFIX_B, 1000);
|
2011-11-22 09:46:04 +01:00
|
|
|
if (tsc_freq < 0 || *err) {
|
2014-06-06 15:21:25 +02:00
|
|
|
error_setg(errp, "bad numerical value %s", val);
|
|
|
|
return;
|
2011-07-07 16:13:12 +02:00
|
|
|
}
|
2013-01-21 15:06:38 +01:00
|
|
|
snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
|
2014-03-03 23:19:19 +01:00
|
|
|
object_property_parse(OBJECT(cpu), num, "tsc-frequency",
|
|
|
|
&local_err);
|
2013-04-26 18:04:32 +02:00
|
|
|
} else if (!strcmp(featurestr, "hv-spinlocks")) {
|
2011-12-18 21:48:13 +01:00
|
|
|
char *err;
|
2013-06-05 15:18:40 +02:00
|
|
|
const int min = 0xFFF;
|
2013-06-04 15:05:25 +02:00
|
|
|
char num[32];
|
2011-12-18 21:48:13 +01:00
|
|
|
numvalue = strtoul(val, &err, 0);
|
|
|
|
if (!*val || *err) {
|
2014-06-06 15:21:25 +02:00
|
|
|
error_setg(errp, "bad numerical value %s", val);
|
|
|
|
return;
|
2011-12-18 21:48:13 +01:00
|
|
|
}
|
2013-06-05 15:18:40 +02:00
|
|
|
if (numvalue < min) {
|
2014-03-03 23:19:19 +01:00
|
|
|
error_report("hv-spinlocks value shall always be >= 0x%x"
|
2014-07-28 09:13:06 +02:00
|
|
|
", fixup will be removed in future versions",
|
|
|
|
min);
|
2013-06-05 15:18:40 +02:00
|
|
|
numvalue = min;
|
|
|
|
}
|
2013-06-04 15:05:25 +02:00
|
|
|
snprintf(num, sizeof(num), "%" PRId32, numvalue);
|
2014-03-03 23:19:19 +01:00
|
|
|
object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
|
2010-03-11 14:38:55 +01:00
|
|
|
} else {
|
2014-03-03 23:19:19 +01:00
|
|
|
object_property_parse(OBJECT(cpu), val, featurestr, &local_err);
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
} else {
|
2012-12-14 01:16:00 +01:00
|
|
|
feat2prop(featurestr);
|
2014-03-03 23:19:19 +01:00
|
|
|
object_property_parse(OBJECT(cpu), "on", featurestr, &local_err);
|
2013-01-21 15:06:38 +01:00
|
|
|
}
|
2014-03-03 23:19:19 +01:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2014-06-06 15:21:25 +02:00
|
|
|
return;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
featurestr = strtok(NULL, ",");
|
|
|
|
}
|
2014-04-30 18:48:37 +02:00
|
|
|
|
2014-08-20 22:30:12 +02:00
|
|
|
if (cpu->host_features) {
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
env->features[w] =
|
|
|
|
x86_cpu_get_supported_feature_word(w, cpu->migratable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-30 18:48:37 +02:00
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
env->features[w] |= plus_features[w];
|
|
|
|
env->features[w] &= ~minus_features[w];
|
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* generate a composite string into buf of all cpuid names in featureset
|
|
|
|
* selected by fbits. indicate truncation at bufsize in the event of overflow.
|
|
|
|
* if flags, suppress names undefined in featureset.
|
|
|
|
*/
|
|
|
|
static void listflags(char *buf, int bufsize, uint32_t fbits,
|
2014-11-05 09:40:33 +01:00
|
|
|
const char **featureset, uint32_t flags)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
|
|
|
const char **p = &featureset[31];
|
|
|
|
char *q, *b, bit;
|
|
|
|
int nc;
|
|
|
|
|
|
|
|
b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
|
|
|
|
*buf = '\0';
|
|
|
|
for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
|
|
|
|
if (fbits & 1 << bit && (*p || !flags)) {
|
|
|
|
if (*p)
|
|
|
|
nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
|
|
|
|
else
|
|
|
|
nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
|
|
|
|
if (bufsize <= nc) {
|
|
|
|
if (b) {
|
|
|
|
memcpy(b, "...", sizeof("..."));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
q += nc;
|
|
|
|
bufsize -= nc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-05 22:41:08 +02:00
|
|
|
/* generate CPU information. */
|
|
|
|
void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
2014-01-30 20:48:58 +01:00
|
|
|
X86CPUDefinition *def;
|
2010-03-11 14:38:55 +01:00
|
|
|
char buf[256];
|
2013-01-21 01:02:28 +01:00
|
|
|
int i;
|
2010-03-11 14:38:55 +01:00
|
|
|
|
2013-01-21 01:02:28 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
|
|
|
def = &builtin_x86_defs[i];
|
2012-09-05 22:41:13 +02:00
|
|
|
snprintf(buf, sizeof(buf), "%s", def->name);
|
2012-09-05 22:41:07 +02:00
|
|
|
(*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
2013-03-24 17:01:02 +01:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
(*cpu_fprintf)(f, "x86 %16s %-48s\n", "host",
|
|
|
|
"KVM processor with all supported host features "
|
|
|
|
"(only available in KVM mode)");
|
|
|
|
#endif
|
|
|
|
|
2012-09-05 22:41:07 +02:00
|
|
|
(*cpu_fprintf)(f, "\nRecognized CPUID flags:\n");
|
2013-02-27 10:15:51 +01:00
|
|
|
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);
|
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
|
2012-08-15 05:17:36 +02:00
|
|
|
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
|
2012-08-10 18:04:14 +02:00
|
|
|
{
|
|
|
|
CpuDefinitionInfoList *cpu_list = NULL;
|
2014-01-30 20:48:58 +01:00
|
|
|
X86CPUDefinition *def;
|
2013-01-21 01:02:28 +01:00
|
|
|
int i;
|
2012-08-10 18:04:14 +02:00
|
|
|
|
2013-01-21 01:02:28 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
2012-08-10 18:04:14 +02:00
|
|
|
CpuDefinitionInfoList *entry;
|
|
|
|
CpuDefinitionInfo *info;
|
|
|
|
|
2013-01-21 01:02:28 +01:00
|
|
|
def = &builtin_x86_defs[i];
|
2012-08-10 18:04:14 +02:00
|
|
|
info = g_malloc0(sizeof(*info));
|
|
|
|
info->name = g_strdup(def->name);
|
|
|
|
|
|
|
|
entry = g_malloc0(sizeof(*entry));
|
|
|
|
entry->value = info;
|
|
|
|
entry->next = cpu_list;
|
|
|
|
cpu_list = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cpu_list;
|
|
|
|
}
|
|
|
|
|
2014-04-30 18:48:41 +02:00
|
|
|
static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
|
bool migratable_only)
|
2014-04-30 18:48:32 +02:00
|
|
|
{
|
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
2014-04-30 18:48:41 +02:00
|
|
|
uint32_t r;
|
2014-04-30 18:48:32 +02:00
|
|
|
|
2014-04-30 18:48:39 +02:00
|
|
|
if (kvm_enabled()) {
|
2014-04-30 18:48:41 +02:00
|
|
|
r = kvm_arch_get_supported_cpuid(kvm_state, wi->cpuid_eax,
|
|
|
|
wi->cpuid_ecx,
|
|
|
|
wi->cpuid_reg);
|
2014-04-30 18:48:39 +02:00
|
|
|
} else if (tcg_enabled()) {
|
2014-04-30 18:48:41 +02:00
|
|
|
r = wi->tcg_features;
|
2014-04-30 18:48:39 +02:00
|
|
|
} else {
|
|
|
|
return ~0;
|
|
|
|
}
|
2014-04-30 18:48:41 +02:00
|
|
|
if (migratable_only) {
|
|
|
|
r &= x86_cpu_get_migratable_flags(w);
|
|
|
|
}
|
|
|
|
return r;
|
2014-04-30 18:48:32 +02:00
|
|
|
}
|
|
|
|
|
2014-04-30 18:48:30 +02:00
|
|
|
/*
|
|
|
|
* Filters CPU feature words based on host availability of each feature.
|
|
|
|
*
|
|
|
|
* Returns: 0 if all flags are supported by the host, non-zero otherwise.
|
|
|
|
*/
|
2014-04-30 18:48:32 +02:00
|
|
|
static int x86_cpu_filter_features(X86CPU *cpu)
|
i386: kvm: filter CPUID feature words earlier, on cpu.c
cpu.c contains the code that will check if all requested CPU features
are available, so the filtering of KVM features must be there, so we can
implement "check" and "enforce" properly.
The only point where kvm_arch_init_vcpu() is called on i386 is:
- cpu_x86_init()
- x86_cpu_realize() (after cpu_x86_register() is called)
- qemu_init_vcpu()
- qemu_kvm_start_vcpu()
- qemu_kvm_thread_fn() (on a new thread)
- kvm_init_vcpu()
- kvm_arch_init_vcpu()
With this patch, the filtering will be done earlier, at:
- cpu_x86_init()
- cpu_x86_register() (before x86_cpu_realize() is called)
Also, the KVM CPUID filtering will now be done at the same place where
the TCG CPUID feature filtering is done. Later, the code can be changed
to use the same filtering code for the "check" and "enforce" modes, as
now the cpu.c code knows exactly which CPU features are going to be
exposed to the guest (and much earlier).
One thing I was worrying about when doing this is that
kvm_arch_get_supported_cpuid() depends on kvm_irqchip_in_kernel(), and
maybe the 'kvm_kernel_irqchip' global variable wasn't initialized yet at
CPU creation time. But kvm_kernel_irqchip is initialized during
kvm_init(), that is called very early (much earlier than the machine
init function), and kvm_init() is already a requirement to run the
GET_SUPPORTED_CPUID ioctl() (as kvm_init() initializes the kvm_state
global variable).
Side note: it would be nice to keep KVM-specific code inside kvm.c. The
problem is that properly implementing -cpu check/enforce code (that's
inside cpu.c) depends directly on the feature bit filtering done using
kvm_arch_get_supported_cpuid(). Currently -cpu check/enforce is broken
because it simply uses the host CPU feature bits instead of
GET_SUPPORTED_CPUID, and we need to fix that.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
2012-10-04 22:49:05 +02:00
|
|
|
{
|
|
|
|
CPUX86State *env = &cpu->env;
|
2013-04-22 21:00:18 +02:00
|
|
|
FeatureWord w;
|
2014-04-30 18:48:30 +02:00
|
|
|
int rv = 0;
|
|
|
|
|
2013-04-22 21:00:18 +02:00
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
2014-04-30 18:48:41 +02:00
|
|
|
uint32_t host_feat =
|
|
|
|
x86_cpu_get_supported_feature_word(w, cpu->migratable);
|
2013-05-06 18:20:08 +02:00
|
|
|
uint32_t requested_features = env->features[w];
|
|
|
|
env->features[w] &= host_feat;
|
|
|
|
cpu->filtered_features[w] = requested_features & ~env->features[w];
|
2014-04-30 18:48:30 +02:00
|
|
|
if (cpu->filtered_features[w]) {
|
|
|
|
if (cpu->check_cpuid || cpu->enforce_cpuid) {
|
2014-04-30 18:48:31 +02:00
|
|
|
report_unavailable_features(w, cpu->filtered_features[w]);
|
2014-04-30 18:48:30 +02:00
|
|
|
}
|
|
|
|
rv = 1;
|
|
|
|
}
|
2013-04-22 21:00:18 +02:00
|
|
|
}
|
2014-04-30 18:48:30 +02:00
|
|
|
|
|
|
|
return rv;
|
i386: kvm: filter CPUID feature words earlier, on cpu.c
cpu.c contains the code that will check if all requested CPU features
are available, so the filtering of KVM features must be there, so we can
implement "check" and "enforce" properly.
The only point where kvm_arch_init_vcpu() is called on i386 is:
- cpu_x86_init()
- x86_cpu_realize() (after cpu_x86_register() is called)
- qemu_init_vcpu()
- qemu_kvm_start_vcpu()
- qemu_kvm_thread_fn() (on a new thread)
- kvm_init_vcpu()
- kvm_arch_init_vcpu()
With this patch, the filtering will be done earlier, at:
- cpu_x86_init()
- cpu_x86_register() (before x86_cpu_realize() is called)
Also, the KVM CPUID filtering will now be done at the same place where
the TCG CPUID feature filtering is done. Later, the code can be changed
to use the same filtering code for the "check" and "enforce" modes, as
now the cpu.c code knows exactly which CPU features are going to be
exposed to the guest (and much earlier).
One thing I was worrying about when doing this is that
kvm_arch_get_supported_cpuid() depends on kvm_irqchip_in_kernel(), and
maybe the 'kvm_kernel_irqchip' global variable wasn't initialized yet at
CPU creation time. But kvm_kernel_irqchip is initialized during
kvm_init(), that is called very early (much earlier than the machine
init function), and kvm_init() is already a requirement to run the
GET_SUPPORTED_CPUID ioctl() (as kvm_init() initializes the kvm_state
global variable).
Side note: it would be nice to keep KVM-specific code inside kvm.c. The
problem is that properly implementing -cpu check/enforce code (that's
inside cpu.c) depends directly on the feature bit filtering done using
kvm_arch_get_supported_cpuid(). Currently -cpu check/enforce is broken
because it simply uses the host CPU feature bits instead of
GET_SUPPORTED_CPUID, and we need to fix that.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
2012-10-04 22:49:05 +02:00
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
/* Load data from X86CPUDefinition
|
2014-01-30 20:48:56 +01:00
|
|
|
*/
|
2014-02-10 11:21:30 +01:00
|
|
|
static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
|
2010-03-11 14:38:55 +01:00
|
|
|
{
|
2012-04-17 12:00:51 +02:00
|
|
|
CPUX86State *env = &cpu->env;
|
2014-02-19 20:39:21 +01:00
|
|
|
const char *vendor;
|
|
|
|
char host_vendor[CPUID_VENDOR_SZ + 1];
|
2014-04-30 18:48:37 +02:00
|
|
|
FeatureWord w;
|
2010-03-11 14:38:55 +01:00
|
|
|
|
2013-02-15 14:06:56 +01:00
|
|
|
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);
|
|
|
|
object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", errp);
|
2011-06-01 03:59:52 +02:00
|
|
|
env->cpuid_xlevel2 = def->xlevel2;
|
2013-09-02 17:06:37 +02:00
|
|
|
cpu->cache_info_passthrough = def->cache_info_passthrough;
|
2013-02-15 14:06:56 +01:00
|
|
|
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
|
2014-04-30 18:48:37 +02:00
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
env->features[w] = def->features[w];
|
|
|
|
}
|
2014-01-30 20:48:54 +01:00
|
|
|
|
2014-01-30 20:48:58 +01:00
|
|
|
/* Special cases not set in the X86CPUDefinition structs: */
|
2014-01-30 20:48:54 +01:00
|
|
|
if (kvm_enabled()) {
|
2014-02-19 15:58:10 +01:00
|
|
|
FeatureWord w;
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
env->features[w] |= kvm_default_features[w];
|
2014-04-30 18:48:28 +02:00
|
|
|
env->features[w] &= ~kvm_default_unset_features[w];
|
2014-02-19 15:58:10 +01:00
|
|
|
}
|
2014-01-30 20:48:54 +01:00
|
|
|
}
|
2014-02-19 15:58:10 +01:00
|
|
|
|
2014-01-30 20:48:54 +01:00
|
|
|
env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
|
2014-01-30 20:48:55 +01:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
2014-02-19 20:39:21 +01:00
|
|
|
vendor = def->vendor;
|
2014-01-30 20:48:55 +01:00
|
|
|
if (kvm_enabled()) {
|
|
|
|
uint32_t ebx = 0, ecx = 0, edx = 0;
|
|
|
|
host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
|
|
|
|
x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx);
|
|
|
|
vendor = host_vendor;
|
|
|
|
}
|
|
|
|
|
|
|
|
object_property_set_str(OBJECT(cpu), vendor, "vendor", errp);
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
|
2013-04-29 18:54:13 +02:00
|
|
|
X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
|
|
|
|
Error **errp)
|
2013-02-01 15:12:13 +01:00
|
|
|
{
|
2013-02-15 14:06:56 +01:00
|
|
|
X86CPU *cpu = NULL;
|
2014-02-10 11:21:30 +01:00
|
|
|
X86CPUClass *xcc;
|
2014-02-10 22:02:44 +01:00
|
|
|
ObjectClass *oc;
|
2013-02-15 14:06:56 +01:00
|
|
|
gchar **model_pieces;
|
|
|
|
char *name, *features;
|
2013-02-01 15:12:13 +01:00
|
|
|
Error *error = NULL;
|
|
|
|
|
2013-02-15 14:06:56 +01:00
|
|
|
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];
|
|
|
|
|
2014-02-10 22:02:44 +01:00
|
|
|
oc = x86_cpu_class_by_name(name);
|
|
|
|
if (oc == NULL) {
|
|
|
|
error_setg(&error, "Unable to find CPU definition: %s", name);
|
|
|
|
goto out;
|
|
|
|
}
|
2014-02-10 11:21:30 +01:00
|
|
|
xcc = X86_CPU_CLASS(oc);
|
|
|
|
|
|
|
|
if (xcc->kvm_required && !kvm_enabled()) {
|
|
|
|
error_setg(&error, "CPU model '%s' requires KVM", name);
|
2014-01-30 20:48:57 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
cpu = X86_CPU(object_new(object_class_get_name(oc)));
|
|
|
|
|
2013-04-29 18:54:13 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
if (icc_bridge == NULL) {
|
|
|
|
error_setg(&error, "Invalid icc-bridge value");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
|
|
|
|
object_unref(OBJECT(cpu));
|
|
|
|
#endif
|
2013-02-01 15:12:13 +01:00
|
|
|
|
2014-03-03 23:19:19 +01:00
|
|
|
x86_cpu_parse_featurestr(CPU(cpu), features, &error);
|
2013-02-15 14:06:56 +01:00
|
|
|
if (error) {
|
|
|
|
goto out;
|
2013-02-01 15:12:13 +01:00
|
|
|
}
|
|
|
|
|
2013-04-11 16:51:40 +02:00
|
|
|
out:
|
2013-08-02 18:56:05 +02:00
|
|
|
if (error != NULL) {
|
|
|
|
error_propagate(errp, error);
|
2014-02-10 22:02:44 +01:00
|
|
|
if (cpu) {
|
|
|
|
object_unref(OBJECT(cpu));
|
|
|
|
cpu = NULL;
|
|
|
|
}
|
2013-08-02 18:56:05 +02:00
|
|
|
}
|
2013-04-11 16:51:40 +02:00
|
|
|
g_strfreev(model_pieces);
|
|
|
|
return cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
X86CPU *cpu_x86_init(const char *cpu_model)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
X86CPU *cpu;
|
|
|
|
|
2013-04-29 18:54:13 +02:00
|
|
|
cpu = cpu_x86_create(cpu_model, NULL, &error);
|
2013-02-01 15:12:13 +01:00
|
|
|
if (error) {
|
2013-02-15 14:06:56 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-04-11 16:51:40 +02:00
|
|
|
object_property_set_bool(OBJECT(cpu), true, "realized", &error);
|
|
|
|
|
2013-02-15 14:06:56 +01:00
|
|
|
out:
|
|
|
|
if (error) {
|
2015-02-12 13:55:05 +01:00
|
|
|
error_report_err(error);
|
2013-02-15 14:06:56 +01:00
|
|
|
if (cpu != NULL) {
|
|
|
|
object_unref(OBJECT(cpu));
|
|
|
|
cpu = NULL;
|
|
|
|
}
|
2013-02-01 15:12:13 +01:00
|
|
|
}
|
|
|
|
return cpu;
|
|
|
|
}
|
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
X86CPUDefinition *cpudef = data;
|
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
|
|
|
|
|
|
|
xcc->cpu_def = cpudef;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_register_cpudef_type(X86CPUDefinition *def)
|
|
|
|
{
|
|
|
|
char *typename = x86_cpu_type_name(def->name);
|
|
|
|
TypeInfo ti = {
|
|
|
|
.name = typename,
|
|
|
|
.parent = TYPE_X86_CPU,
|
|
|
|
.class_init = x86_cpu_cpudef_class_init,
|
|
|
|
.class_data = def,
|
|
|
|
};
|
|
|
|
|
|
|
|
type_register(&ti);
|
|
|
|
g_free(typename);
|
|
|
|
}
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
|
2010-06-19 09:42:34 +02:00
|
|
|
void cpu_clear_apic_feature(CPUX86State *env)
|
|
|
|
{
|
2013-04-22 21:00:15 +02:00
|
|
|
env->features[FEAT_1_EDX] &= ~CPUID_APIC;
|
2010-06-19 09:42:34 +02:00
|
|
|
}
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
#endif /* !CONFIG_USER_ONLY */
|
|
|
|
|
2012-09-05 22:41:13 +02:00
|
|
|
/* Initialize list of CPU models, filling some non-static fields if necessary
|
2010-03-11 14:38:55 +01:00
|
|
|
*/
|
|
|
|
void x86_cpudef_setup(void)
|
|
|
|
{
|
2012-05-30 05:35:51 +02:00
|
|
|
int i, j;
|
|
|
|
static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" };
|
2010-03-11 14:38:55 +01:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
|
2014-01-30 20:48:58 +01:00
|
|
|
X86CPUDefinition *def = &builtin_x86_defs[i];
|
2012-05-30 05:35:51 +02:00
|
|
|
|
|
|
|
/* Look for specific "cpudef" models that */
|
2012-06-20 06:05:51 +02:00
|
|
|
/* have the QEMU version in .model_id */
|
2012-05-30 05:35:51 +02:00
|
|
|
for (j = 0; j < ARRAY_SIZE(model_with_versions); j++) {
|
2012-09-05 22:41:12 +02:00
|
|
|
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_get_version());
|
2012-05-30 05:35:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
|
|
|
|
uint32_t *ecx, uint32_t *edx)
|
|
|
|
{
|
|
|
|
*ebx = env->cpuid_vendor1;
|
|
|
|
*edx = env->cpuid_vendor2;
|
|
|
|
*ecx = env->cpuid_vendor3;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|
|
|
uint32_t *eax, uint32_t *ebx,
|
|
|
|
uint32_t *ecx, uint32_t *edx)
|
|
|
|
{
|
2012-12-01 05:35:08 +01:00
|
|
|
X86CPU *cpu = x86_env_get_cpu(env);
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
|
2010-03-11 14:38:55 +01:00
|
|
|
/* test if maximum index reached */
|
|
|
|
if (index & 0x80000000) {
|
2011-06-01 03:59:52 +02:00
|
|
|
if (index > env->cpuid_xlevel) {
|
|
|
|
if (env->cpuid_xlevel2 > 0) {
|
|
|
|
/* Handle the Centaur's CPUID instruction. */
|
|
|
|
if (index > env->cpuid_xlevel2) {
|
|
|
|
index = env->cpuid_xlevel2;
|
|
|
|
} else if (index < 0xC0000000) {
|
|
|
|
index = env->cpuid_xlevel;
|
|
|
|
}
|
|
|
|
} else {
|
target-i386: CPUID: return highest basic leaf if eax > cpuid_xlevel
This fixes a subtle bug. A bug that probably won't cause trouble for any
existing OS, but a bug anyway:
Intel SDM Volume 2, CPUID Instruction states:
> Two types of information are returned: basic and extended function
> information. If a value entered for CPUID.EAX is higher than the maximum
> input value for basic or extended function for that processor then the
> data for the highest basic information leaf is returned. For example,
> using the Intel Core i7 processor, the following is true:
>
> CPUID.EAX = 05H (* Returns MONITOR/MWAIT leaf. *)
> CPUID.EAX = 0AH (* Returns Architectural Performance Monitoring leaf. *)
> CPUID.EAX = 0BH (* Returns Extended Topology Enumeration leaf. *)
> CPUID.EAX = 0CH (* INVALID: Returns the same information as CPUID.EAX = 0BH. *)
> CPUID.EAX = 80000008H (* Returns linear/physical address size data. *)
> CPUID.EAX = 8000000AH (* INVALID: Returns same information as CPUID.EAX = 0BH. *)
AMD's CPUID Specification, on the other hand, is less specific:
> The CPUID instruction supports two sets or ranges of functions,
> standard and extended.
>
> • The smallest function number of the standard function range is
> Fn0000_0000. The largest function num- ber of the standard function
> range, for a particular implementation, is returned in CPUID
> Fn0000_0000_EAX.
>
> • The smallest function number of the extended function range is
> Fn8000_0000. The largest function num- ber of the extended function
> range, for a particular implementation, is returned in CPUID
> Fn8000_0000_EAX.
>
> Functions that are neither standard nor extended are undefined and
> should not be relied upon.
QEMU's behavior matched Intel's specification before, but this was
changed by commit b3baa152aaef1905876670590275c2dd0bbb088c. This patch
restores the behavior documented by Intel when cpuid_xlevel2 is 0.
The existing behavior when cpuid_xlevel2 is set (falling back to
level=cpuid_xlevel) is being kept, as I couldn't find any public
documentation on the CPUID 0xC0000000 function range on Centaur CPUs.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2012-12-20 19:43:48 +01:00
|
|
|
/* Intel documentation states that invalid EAX input will
|
|
|
|
* return the same information as EAX=cpuid_level
|
|
|
|
* (Intel SDM Vol. 2A - Instruction Set Reference - CPUID)
|
|
|
|
*/
|
|
|
|
index = env->cpuid_level;
|
2011-06-01 03:59:52 +02:00
|
|
|
}
|
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
} else {
|
|
|
|
if (index > env->cpuid_level)
|
|
|
|
index = env->cpuid_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(index) {
|
|
|
|
case 0:
|
|
|
|
*eax = env->cpuid_level;
|
|
|
|
get_cpuid_vendor(env, ebx, ecx, edx);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
*eax = env->cpuid_version;
|
|
|
|
*ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
|
2013-04-22 21:00:15 +02:00
|
|
|
*ecx = env->features[FEAT_1_ECX];
|
|
|
|
*edx = env->features[FEAT_1_EDX];
|
2012-12-17 03:27:07 +01:00
|
|
|
if (cs->nr_cores * cs->nr_threads > 1) {
|
|
|
|
*ebx |= (cs->nr_cores * cs->nr_threads) << 16;
|
2010-03-11 14:38:55 +01:00
|
|
|
*edx |= 1 << 28; /* HTT bit */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
/* cache info: needed for Pentium Pro compatibility */
|
2013-09-02 17:06:37 +02:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-27 17:24:37 +02:00
|
|
|
*eax = 1; /* Number of CPUID[EAX=2] calls required */
|
2010-03-11 14:38:55 +01:00
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
2013-08-27 17:24:37 +02:00
|
|
|
*edx = (L1D_DESCRIPTOR << 16) | \
|
|
|
|
(L1I_DESCRIPTOR << 8) | \
|
|
|
|
(L2_DESCRIPTOR);
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
/* cache info: needed for Core compatibility */
|
2013-09-02 17:06:37 +02:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, count, eax, ebx, ecx, edx);
|
2013-11-19 17:49:46 +01:00
|
|
|
*eax &= ~0xFC000000;
|
2010-03-11 14:38:55 +01:00
|
|
|
} else {
|
2010-03-13 16:46:33 +01:00
|
|
|
*eax = 0;
|
2013-11-19 17:49:46 +01:00
|
|
|
switch (count) {
|
2010-03-11 14:38:55 +01:00
|
|
|
case 0: /* L1 dcache info */
|
2013-08-27 17:24:37 +02:00
|
|
|
*eax |= CPUID_4_TYPE_DCACHE | \
|
|
|
|
CPUID_4_LEVEL(1) | \
|
|
|
|
CPUID_4_SELF_INIT_LEVEL;
|
|
|
|
*ebx = (L1D_LINE_SIZE - 1) | \
|
|
|
|
((L1D_PARTITIONS - 1) << 12) | \
|
|
|
|
((L1D_ASSOCIATIVITY - 1) << 22);
|
|
|
|
*ecx = L1D_SETS - 1;
|
|
|
|
*edx = CPUID_4_NO_INVD_SHARING;
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
|
|
|
case 1: /* L1 icache info */
|
2013-08-27 17:24:37 +02:00
|
|
|
*eax |= CPUID_4_TYPE_ICACHE | \
|
|
|
|
CPUID_4_LEVEL(1) | \
|
|
|
|
CPUID_4_SELF_INIT_LEVEL;
|
|
|
|
*ebx = (L1I_LINE_SIZE - 1) | \
|
|
|
|
((L1I_PARTITIONS - 1) << 12) | \
|
|
|
|
((L1I_ASSOCIATIVITY - 1) << 22);
|
|
|
|
*ecx = L1I_SETS - 1;
|
|
|
|
*edx = CPUID_4_NO_INVD_SHARING;
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
|
|
|
case 2: /* L2 cache info */
|
2013-08-27 17:24:37 +02:00
|
|
|
*eax |= CPUID_4_TYPE_UNIFIED | \
|
|
|
|
CPUID_4_LEVEL(2) | \
|
|
|
|
CPUID_4_SELF_INIT_LEVEL;
|
2012-12-17 03:27:07 +01:00
|
|
|
if (cs->nr_threads > 1) {
|
|
|
|
*eax |= (cs->nr_threads - 1) << 14;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
2013-08-27 17:24:37 +02:00
|
|
|
*ebx = (L2_LINE_SIZE - 1) | \
|
|
|
|
((L2_PARTITIONS - 1) << 12) | \
|
|
|
|
((L2_ASSOCIATIVITY - 1) << 22);
|
|
|
|
*ecx = L2_SETS - 1;
|
|
|
|
*edx = CPUID_4_NO_INVD_SHARING;
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
|
|
|
default: /* end of info */
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
2013-11-19 17:49:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* QEMU gives out its own APIC IDs, never pass down bits 31..26. */
|
|
|
|
if ((*eax & 31) && cs->nr_cores > 1) {
|
|
|
|
*eax |= (cs->nr_cores - 1) << 26;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
/* mwait info: needed for Core compatibility */
|
|
|
|
*eax = 0; /* Smallest monitor-line size in bytes */
|
|
|
|
*ebx = 0; /* Largest monitor-line size in bytes */
|
|
|
|
*ecx = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
/* Thermal and Power Leaf */
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
2011-05-30 17:17:42 +02:00
|
|
|
case 7:
|
Expose CPUID leaf 7 only for -cpu host
Changes v2 -> v3;
- Check for kvm_enabled() before setting cpuid_7_0_ebx_features
Changes v1 -> v2:
- Use kvm_arch_get_supported_cpuid() instead of host_cpuid() on
cpu_x86_fill_host().
We should use GET_SUPPORTED_CPUID for all bits on "-cpu host"
eventually, but I am not changing all the other CPUID leaves because
we may not be able to test such an intrusive change in time for 1.1.
Description of the bug:
Since QEMU 0.15, the CPUID information on CPUID[EAX=7,ECX=0] is being
returned unfiltered to the guest, directly from the GET_SUPPORTED_CPUID
return value.
The problem is that this makes the resulting CPU feature flags
unpredictable and dependent on the host CPU and kernel version. This
breaks live-migration badly if migrating from a host CPU that supports
some features on that CPUID leaf (running a recent kernel) to a kernel
or host CPU that doesn't support it.
Migration also is incorrect (the virtual CPU changes under the guest's
feet) if you migrate in the opposite direction (from an old CPU/kernel
to a new CPU/kernel), but with less serious consequences (guests
normally query CPUID information only once on boot).
Fortunately, the bug affects only users using cpudefs with level >= 7.
The right behavior should be to explicitly enable those features on
[cpudef] config sections or on the "-cpu" command-line arguments. Right
now there is no predefined CPU model on QEMU that has those features:
the latest Intel model we have is Sandy Bridge.
I would like to get this fixed on 1.1, so I am submitting this patch,
that enables those features only if "-cpu host" is being used (as we
don't have any pre-defined CPU model that actually have those features).
After 1.1 is released, we can make those features properly configurable
on [cpudef] and -cpu configuration.
One problem is: with this patch, users with the following setup:
- Running QEMU 1.0;
- Using a cpudef having level >= 7;
- Running a kernel that supports the features on CPUID leaf 7; and
- Running on a CPU that supports some features on CPUID leaf 7
won't be able to live-migrate to QEMU 1.1. But for these users
live-migration is already broken (they can't live-migrate to hosts with
older CPUs or older kernels, already), I don't see how to avoid this
problem.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2012-05-21 16:27:02 +02:00
|
|
|
/* Structured Extended Feature Flags Enumeration Leaf */
|
|
|
|
if (count == 0) {
|
|
|
|
*eax = 0; /* Maximum ECX value for sub-leaves */
|
2013-04-22 21:00:15 +02:00
|
|
|
*ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */
|
Expose CPUID leaf 7 only for -cpu host
Changes v2 -> v3;
- Check for kvm_enabled() before setting cpuid_7_0_ebx_features
Changes v1 -> v2:
- Use kvm_arch_get_supported_cpuid() instead of host_cpuid() on
cpu_x86_fill_host().
We should use GET_SUPPORTED_CPUID for all bits on "-cpu host"
eventually, but I am not changing all the other CPUID leaves because
we may not be able to test such an intrusive change in time for 1.1.
Description of the bug:
Since QEMU 0.15, the CPUID information on CPUID[EAX=7,ECX=0] is being
returned unfiltered to the guest, directly from the GET_SUPPORTED_CPUID
return value.
The problem is that this makes the resulting CPU feature flags
unpredictable and dependent on the host CPU and kernel version. This
breaks live-migration badly if migrating from a host CPU that supports
some features on that CPUID leaf (running a recent kernel) to a kernel
or host CPU that doesn't support it.
Migration also is incorrect (the virtual CPU changes under the guest's
feet) if you migrate in the opposite direction (from an old CPU/kernel
to a new CPU/kernel), but with less serious consequences (guests
normally query CPUID information only once on boot).
Fortunately, the bug affects only users using cpudefs with level >= 7.
The right behavior should be to explicitly enable those features on
[cpudef] config sections or on the "-cpu" command-line arguments. Right
now there is no predefined CPU model on QEMU that has those features:
the latest Intel model we have is Sandy Bridge.
I would like to get this fixed on 1.1, so I am submitting this patch,
that enables those features only if "-cpu host" is being used (as we
don't have any pre-defined CPU model that actually have those features).
After 1.1 is released, we can make those features properly configurable
on [cpudef] and -cpu configuration.
One problem is: with this patch, users with the following setup:
- Running QEMU 1.0;
- Using a cpudef having level >= 7;
- Running a kernel that supports the features on CPUID leaf 7; and
- Running on a CPU that supports some features on CPUID leaf 7
won't be able to live-migrate to QEMU 1.1. But for these users
live-migration is already broken (they can't live-migrate to hosts with
older CPUs or older kernels, already), I don't see how to avoid this
problem.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2012-05-21 16:27:02 +02:00
|
|
|
*ecx = 0; /* Reserved */
|
|
|
|
*edx = 0; /* Reserved */
|
2011-05-30 17:17:42 +02:00
|
|
|
} else {
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
}
|
|
|
|
break;
|
2010-03-11 14:38:55 +01:00
|
|
|
case 9:
|
|
|
|
/* Direct Cache Access Information Leaf */
|
|
|
|
*eax = 0; /* Bits 0-31 in DCA_CAP MSR */
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
case 0xA:
|
|
|
|
/* Architectural Performance Monitoring Leaf */
|
2013-07-26 22:09:36 +02:00
|
|
|
if (kvm_enabled() && cpu->enable_pmu) {
|
2012-12-01 05:35:08 +01:00
|
|
|
KVMState *s = cs->kvm_state;
|
2011-12-15 11:44:05 +01:00
|
|
|
|
|
|
|
*eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX);
|
|
|
|
*ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX);
|
|
|
|
*ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX);
|
|
|
|
*edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX);
|
|
|
|
} else {
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
2013-10-02 17:54:57 +02:00
|
|
|
case 0xD: {
|
|
|
|
KVMState *s = cs->kvm_state;
|
|
|
|
uint64_t kvm_mask;
|
|
|
|
int i;
|
|
|
|
|
2010-06-17 09:18:14 +02:00
|
|
|
/* Processor Extended State */
|
2013-10-02 17:54:57 +02:00
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) || !kvm_enabled()) {
|
2010-06-17 09:18:14 +02:00
|
|
|
break;
|
|
|
|
}
|
2013-10-02 17:54:57 +02:00
|
|
|
kvm_mask =
|
|
|
|
kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX) |
|
|
|
|
((uint64_t)kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX) << 32);
|
2011-06-08 16:11:05 +02:00
|
|
|
|
2013-10-02 17:54:57 +02:00
|
|
|
if (count == 0) {
|
|
|
|
*ecx = 0x240;
|
|
|
|
for (i = 2; i < ARRAY_SIZE(ext_save_areas); i++) {
|
|
|
|
const ExtSaveArea *esa = &ext_save_areas[i];
|
|
|
|
if ((env->features[esa->feature] & esa->bits) == esa->bits &&
|
|
|
|
(kvm_mask & (1 << i)) != 0) {
|
|
|
|
if (i < 32) {
|
|
|
|
*eax |= 1 << i;
|
|
|
|
} else {
|
|
|
|
*edx |= 1 << (i - 32);
|
|
|
|
}
|
|
|
|
*ecx = MAX(*ecx, esa->offset + esa->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*eax |= kvm_mask & (XSTATE_FP | XSTATE_SSE);
|
|
|
|
*ebx = *ecx;
|
|
|
|
} else if (count == 1) {
|
2014-11-24 15:54:43 +01:00
|
|
|
*eax = env->features[FEAT_XSAVE];
|
2013-10-02 17:54:57 +02:00
|
|
|
} else if (count < ARRAY_SIZE(ext_save_areas)) {
|
|
|
|
const ExtSaveArea *esa = &ext_save_areas[count];
|
|
|
|
if ((env->features[esa->feature] & esa->bits) == esa->bits &&
|
|
|
|
(kvm_mask & (1 << count)) != 0) {
|
2013-12-02 21:17:50 +01:00
|
|
|
*eax = esa->size;
|
|
|
|
*ebx = esa->offset;
|
2013-10-02 17:54:57 +02:00
|
|
|
}
|
2010-06-17 09:18:14 +02:00
|
|
|
}
|
|
|
|
break;
|
2013-10-02 17:54:57 +02:00
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
case 0x80000000:
|
|
|
|
*eax = env->cpuid_xlevel;
|
|
|
|
*ebx = env->cpuid_vendor1;
|
|
|
|
*edx = env->cpuid_vendor2;
|
|
|
|
*ecx = env->cpuid_vendor3;
|
|
|
|
break;
|
|
|
|
case 0x80000001:
|
|
|
|
*eax = env->cpuid_version;
|
|
|
|
*ebx = 0;
|
2013-04-22 21:00:15 +02:00
|
|
|
*ecx = env->features[FEAT_8000_0001_ECX];
|
|
|
|
*edx = env->features[FEAT_8000_0001_EDX];
|
2010-03-11 14:38:55 +01:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2012-12-17 03:27:07 +01:00
|
|
|
if (cs->nr_cores * cs->nr_threads > 1) {
|
2010-03-11 14:38:55 +01:00
|
|
|
uint32_t tebx, tecx, tedx;
|
|
|
|
get_cpuid_vendor(env, &tebx, &tecx, &tedx);
|
|
|
|
if (tebx != CPUID_VENDOR_INTEL_1 ||
|
|
|
|
tedx != CPUID_VENDOR_INTEL_2 ||
|
|
|
|
tecx != CPUID_VENDOR_INTEL_3) {
|
|
|
|
*ecx |= 1 << 1; /* CmpLegacy bit */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x80000002:
|
|
|
|
case 0x80000003:
|
|
|
|
case 0x80000004:
|
|
|
|
*eax = env->cpuid_model[(index - 0x80000002) * 4 + 0];
|
|
|
|
*ebx = env->cpuid_model[(index - 0x80000002) * 4 + 1];
|
|
|
|
*ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2];
|
|
|
|
*edx = env->cpuid_model[(index - 0x80000002) * 4 + 3];
|
|
|
|
break;
|
|
|
|
case 0x80000005:
|
|
|
|
/* cache info (L1 cache) */
|
2013-09-02 17:06:37 +02:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-27 17:24:37 +02:00
|
|
|
*eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \
|
|
|
|
(L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES);
|
|
|
|
*ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \
|
|
|
|
(L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES);
|
|
|
|
*ecx = (L1D_SIZE_KB_AMD << 24) | (L1D_ASSOCIATIVITY_AMD << 16) | \
|
|
|
|
(L1D_LINES_PER_TAG << 8) | (L1D_LINE_SIZE);
|
|
|
|
*edx = (L1I_SIZE_KB_AMD << 24) | (L1I_ASSOCIATIVITY_AMD << 16) | \
|
|
|
|
(L1I_LINES_PER_TAG << 8) | (L1I_LINE_SIZE);
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
|
|
|
case 0x80000006:
|
|
|
|
/* cache info (L2 cache) */
|
2013-09-02 17:06:37 +02:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-27 17:24:37 +02:00
|
|
|
*eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \
|
|
|
|
(L2_DTLB_2M_ENTRIES << 16) | \
|
|
|
|
(AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \
|
|
|
|
(L2_ITLB_2M_ENTRIES);
|
|
|
|
*ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | \
|
|
|
|
(L2_DTLB_4K_ENTRIES << 16) | \
|
|
|
|
(AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \
|
|
|
|
(L2_ITLB_4K_ENTRIES);
|
|
|
|
*ecx = (L2_SIZE_KB_AMD << 16) | \
|
|
|
|
(AMD_ENC_ASSOC(L2_ASSOCIATIVITY) << 12) | \
|
|
|
|
(L2_LINES_PER_TAG << 8) | (L2_LINE_SIZE);
|
|
|
|
*edx = ((L3_SIZE_KB/512) << 18) | \
|
|
|
|
(AMD_ENC_ASSOC(L3_ASSOCIATIVITY) << 12) | \
|
|
|
|
(L3_LINES_PER_TAG << 8) | (L3_LINE_SIZE);
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
2014-04-30 18:48:45 +02:00
|
|
|
case 0x80000007:
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = env->features[FEAT_8000_0007_EDX];
|
|
|
|
break;
|
2010-03-11 14:38:55 +01:00
|
|
|
case 0x80000008:
|
|
|
|
/* virtual & phys address size in low 2 bytes. */
|
|
|
|
/* XXX: This value must match the one used in the MMU code. */
|
2013-04-22 21:00:15 +02:00
|
|
|
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
2010-03-11 14:38:55 +01:00
|
|
|
/* 64 bit processor */
|
|
|
|
/* XXX: The physical address space is limited to 42 bits in exec.c. */
|
2013-04-11 22:07:23 +02:00
|
|
|
*eax = 0x00003028; /* 48 bits virtual, 40 bits physical */
|
2010-03-11 14:38:55 +01:00
|
|
|
} else {
|
2013-04-22 21:00:15 +02:00
|
|
|
if (env->features[FEAT_1_EDX] & CPUID_PSE36) {
|
2010-03-11 14:38:55 +01:00
|
|
|
*eax = 0x00000024; /* 36 bits physical */
|
2013-04-11 22:07:23 +02:00
|
|
|
} else {
|
2010-03-11 14:38:55 +01:00
|
|
|
*eax = 0x00000020; /* 32 bits physical */
|
2013-04-11 22:07:23 +02:00
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
2012-12-17 03:27:07 +01:00
|
|
|
if (cs->nr_cores * cs->nr_threads > 1) {
|
|
|
|
*ecx |= (cs->nr_cores * cs->nr_threads) - 1;
|
2010-03-11 14:38:55 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x8000000A:
|
2013-04-22 21:00:15 +02:00
|
|
|
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
|
2012-12-04 20:34:38 +01:00
|
|
|
*eax = 0x00000001; /* SVM Revision */
|
|
|
|
*ebx = 0x00000010; /* nr of ASIDs */
|
|
|
|
*ecx = 0;
|
2013-04-22 21:00:15 +02:00
|
|
|
*edx = env->features[FEAT_SVM]; /* optional features */
|
2012-12-04 20:34:38 +01:00
|
|
|
} else {
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
}
|
2010-03-11 14:38:55 +01:00
|
|
|
break;
|
2011-06-01 03:59:52 +02:00
|
|
|
case 0xC0000000:
|
|
|
|
*eax = env->cpuid_xlevel2;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
case 0xC0000001:
|
|
|
|
/* Support for VIA CPU's CPUID instruction */
|
|
|
|
*eax = env->cpuid_version;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
2013-04-22 21:00:15 +02:00
|
|
|
*edx = env->features[FEAT_C000_0001_EDX];
|
2011-06-01 03:59:52 +02:00
|
|
|
break;
|
|
|
|
case 0xC0000002:
|
|
|
|
case 0xC0000003:
|
|
|
|
case 0xC0000004:
|
|
|
|
/* Reserved for the future, and now filled with zero */
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
2010-03-11 14:38:55 +01:00
|
|
|
default:
|
|
|
|
/* reserved values: zero */
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-04-02 23:20:08 +02:00
|
|
|
|
|
|
|
/* CPUClass::reset() */
|
|
|
|
static void x86_cpu_reset(CPUState *s)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(s);
|
|
|
|
X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
|
|
|
|
CPUX86State *env = &cpu->env;
|
2012-04-03 00:16:24 +02:00
|
|
|
int i;
|
|
|
|
|
2012-04-02 23:20:08 +02:00
|
|
|
xcc->parent_reset(s);
|
|
|
|
|
2013-03-12 13:16:28 +01:00
|
|
|
memset(env, 0, offsetof(CPUX86State, cpuid_level));
|
2012-04-03 00:16:24 +02:00
|
|
|
|
2013-09-04 02:19:44 +02:00
|
|
|
tlb_flush(s, 1);
|
2012-04-03 00:16:24 +02:00
|
|
|
|
|
|
|
env->old_exception = -1;
|
|
|
|
|
|
|
|
/* init to reset state */
|
|
|
|
|
|
|
|
#ifdef CONFIG_SOFTMMU
|
|
|
|
env->hflags |= HF_SOFTMMU_MASK;
|
|
|
|
#endif
|
|
|
|
env->hflags2 |= HF2_GIF_MASK;
|
|
|
|
|
|
|
|
cpu_x86_update_cr0(env, 0x60000010);
|
|
|
|
env->a20_mask = ~0x0;
|
|
|
|
env->smbase = 0x30000;
|
|
|
|
|
|
|
|
env->idt.limit = 0xffff;
|
|
|
|
env->gdt.limit = 0xffff;
|
|
|
|
env->ldt.limit = 0xffff;
|
|
|
|
env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
|
|
|
|
env->tr.limit = 0xffff;
|
|
|
|
env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
|
|
|
|
|
|
|
|
cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
|
|
|
|
DESC_R_MASK | DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
|
|
|
|
env->eip = 0xfff0;
|
|
|
|
env->regs[R_EDX] = env->cpuid_version;
|
|
|
|
|
|
|
|
env->eflags = 0x2;
|
|
|
|
|
|
|
|
/* FPU init */
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
env->fptags[i] = 1;
|
|
|
|
}
|
2014-09-17 10:05:19 +02:00
|
|
|
cpu_set_fpuc(env, 0x37f);
|
2012-04-03 00:16:24 +02:00
|
|
|
|
|
|
|
env->mxcsr = 0x1f80;
|
2013-09-13 15:55:57 +02:00
|
|
|
env->xstate_bv = XSTATE_FP | XSTATE_SSE;
|
2012-04-03 00:16:24 +02:00
|
|
|
|
|
|
|
env->pat = 0x0007040600070406ULL;
|
|
|
|
env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
|
|
|
|
|
|
|
|
memset(env->dr, 0, sizeof(env->dr));
|
|
|
|
env->dr[6] = DR6_FIXED_1;
|
|
|
|
env->dr[7] = DR7_FIXED_1;
|
2013-09-02 17:26:20 +02:00
|
|
|
cpu_breakpoint_remove_all(s, BP_CPU);
|
2013-09-02 16:57:02 +02:00
|
|
|
cpu_watchpoint_remove_all(s, BP_CPU);
|
2012-07-23 15:22:27 +02:00
|
|
|
|
2014-04-29 13:10:05 +02:00
|
|
|
env->xcr0 = 1;
|
2013-12-06 09:33:01 +01:00
|
|
|
|
2014-08-14 23:39:39 +02:00
|
|
|
/*
|
|
|
|
* SDM 11.11.5 requires:
|
|
|
|
* - IA32_MTRR_DEF_TYPE MSR.E = 0
|
|
|
|
* - IA32_MTRR_PHYSMASKn.V = 0
|
|
|
|
* All other bits are undefined. For simplification, zero it all.
|
|
|
|
*/
|
|
|
|
env->mtrr_deftype = 0;
|
|
|
|
memset(env->mtrr_var, 0, sizeof(env->mtrr_var));
|
|
|
|
memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed));
|
|
|
|
|
2012-07-23 15:22:27 +02:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
/* We hard-wire the BSP to the first CPU. */
|
2012-12-17 06:18:02 +01:00
|
|
|
if (s->cpu_index == 0) {
|
2013-12-23 10:04:02 +01:00
|
|
|
apic_designate_bsp(cpu->apic_state);
|
2012-07-23 15:22:27 +02:00
|
|
|
}
|
|
|
|
|
2013-01-17 18:51:17 +01:00
|
|
|
s->halted = !cpu_is_bsp(cpu);
|
2013-03-20 13:11:56 +01:00
|
|
|
|
|
|
|
if (kvm_enabled()) {
|
|
|
|
kvm_arch_reset_vcpu(cpu);
|
|
|
|
}
|
2012-07-23 15:22:27 +02:00
|
|
|
#endif
|
2012-04-02 23:20:08 +02:00
|
|
|
}
|
|
|
|
|
2012-07-23 15:22:27 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
bool cpu_is_bsp(X86CPU *cpu)
|
|
|
|
{
|
2013-12-23 10:04:02 +01:00
|
|
|
return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP;
|
2012-07-23 15:22:27 +02:00
|
|
|
}
|
2012-07-23 15:22:28 +02:00
|
|
|
|
|
|
|
/* TODO: remove me, when reset over QOM tree is implemented */
|
|
|
|
static void x86_cpu_machine_reset_cb(void *opaque)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = opaque;
|
|
|
|
cpu_reset(CPU(cpu));
|
|
|
|
}
|
2012-07-23 15:22:27 +02:00
|
|
|
#endif
|
|
|
|
|
2012-04-03 00:00:17 +02:00
|
|
|
static void mce_init(X86CPU *cpu)
|
|
|
|
{
|
|
|
|
CPUX86State *cenv = &cpu->env;
|
|
|
|
unsigned int bank;
|
|
|
|
|
|
|
|
if (((cenv->cpuid_version >> 8) & 0xf) >= 6
|
2013-04-22 21:00:15 +02:00
|
|
|
&& (cenv->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
|
2012-04-03 00:00:17 +02:00
|
|
|
(CPUID_MCE | CPUID_MCA)) {
|
|
|
|
cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
|
|
|
|
cenv->mcg_ctl = ~(uint64_t)0;
|
|
|
|
for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
|
|
|
|
cenv->mce_banks[bank * 4] = ~(uint64_t)0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-13 22:35:39 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2013-04-05 16:36:54 +02:00
|
|
|
static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
|
2012-10-13 22:35:39 +02:00
|
|
|
{
|
|
|
|
CPUX86State *env = &cpu->env;
|
2013-04-29 19:03:01 +02:00
|
|
|
DeviceState *dev = DEVICE(cpu);
|
2012-10-10 12:18:02 +02:00
|
|
|
APICCommonState *apic;
|
2012-10-13 22:35:39 +02:00
|
|
|
const char *apic_type = "apic";
|
|
|
|
|
|
|
|
if (kvm_irqchip_in_kernel()) {
|
|
|
|
apic_type = "kvm-apic";
|
|
|
|
} else if (xen_enabled()) {
|
|
|
|
apic_type = "xen-apic";
|
|
|
|
}
|
|
|
|
|
2013-12-23 10:04:02 +01:00
|
|
|
cpu->apic_state = qdev_try_create(qdev_get_parent_bus(dev), apic_type);
|
|
|
|
if (cpu->apic_state == NULL) {
|
2012-10-13 22:35:39 +02:00
|
|
|
error_setg(errp, "APIC device '%s' could not be created", apic_type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
object_property_add_child(OBJECT(cpu), "apic",
|
2013-12-23 10:04:02 +01:00
|
|
|
OBJECT(cpu->apic_state), NULL);
|
|
|
|
qdev_prop_set_uint8(cpu->apic_state, "id", env->cpuid_apic_id);
|
2012-10-13 22:35:39 +02:00
|
|
|
/* TODO: convert to link<> */
|
2013-12-23 10:04:02 +01:00
|
|
|
apic = APIC_COMMON(cpu->apic_state);
|
2012-10-10 14:10:07 +02:00
|
|
|
apic->cpu = cpu;
|
2013-04-05 16:36:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
|
|
|
|
{
|
2013-12-23 10:04:02 +01:00
|
|
|
if (cpu->apic_state == NULL) {
|
2013-04-05 16:36:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2012-10-13 22:35:39 +02:00
|
|
|
|
2013-12-23 10:04:02 +01:00
|
|
|
if (qdev_init(cpu->apic_state)) {
|
2012-10-13 22:35:39 +02:00
|
|
|
error_setg(errp, "APIC device '%s' could not be initialized",
|
2013-12-23 10:04:02 +01:00
|
|
|
object_get_typename(OBJECT(cpu->apic_state)));
|
2012-10-13 22:35:39 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-04-05 16:36:54 +02:00
|
|
|
#else
|
|
|
|
static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
|
|
|
|
{
|
|
|
|
}
|
2012-10-13 22:35:39 +02:00
|
|
|
#endif
|
|
|
|
|
2014-10-21 17:00:45 +02:00
|
|
|
|
|
|
|
#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \
|
|
|
|
(env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \
|
|
|
|
(env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3)
|
|
|
|
#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && \
|
|
|
|
(env)->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && \
|
|
|
|
(env)->cpuid_vendor3 == CPUID_VENDOR_AMD_3)
|
2013-01-16 03:41:47 +01:00
|
|
|
static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
2012-05-09 23:15:32 +02:00
|
|
|
{
|
2013-07-27 02:53:25 +02:00
|
|
|
CPUState *cs = CPU(dev);
|
2013-01-16 03:41:47 +01:00
|
|
|
X86CPU *cpu = X86_CPU(dev);
|
|
|
|
X86CPUClass *xcc = X86_CPU_GET_CLASS(dev);
|
2012-10-22 17:03:00 +02:00
|
|
|
CPUX86State *env = &cpu->env;
|
2013-01-16 03:41:47 +01:00
|
|
|
Error *local_err = NULL;
|
2014-10-21 17:00:45 +02:00
|
|
|
static bool ht_warned;
|
2012-10-22 17:03:00 +02:00
|
|
|
|
2013-04-22 21:00:15 +02:00
|
|
|
if (env->features[FEAT_7_0_EBX] && env->cpuid_level < 7) {
|
2012-10-22 17:03:00 +02:00
|
|
|
env->cpuid_level = 7;
|
|
|
|
}
|
2012-05-09 23:15:32 +02:00
|
|
|
|
2012-12-28 21:01:17 +01:00
|
|
|
/* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
|
|
|
|
* CPUID[1].EDX.
|
|
|
|
*/
|
2014-10-21 17:00:45 +02:00
|
|
|
if (IS_AMD_CPU(env)) {
|
2013-04-22 21:00:15 +02:00
|
|
|
env->features[FEAT_8000_0001_EDX] &= ~CPUID_EXT2_AMD_ALIASES;
|
|
|
|
env->features[FEAT_8000_0001_EDX] |= (env->features[FEAT_1_EDX]
|
2012-12-28 21:01:17 +01:00
|
|
|
& CPUID_EXT2_AMD_ALIASES);
|
|
|
|
}
|
|
|
|
|
2014-04-30 18:48:39 +02:00
|
|
|
|
|
|
|
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;
|
2012-12-28 21:01:16 +01:00
|
|
|
}
|
|
|
|
|
2012-07-23 15:22:28 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
|
2012-10-13 22:35:39 +02:00
|
|
|
|
2013-04-22 21:00:15 +02:00
|
|
|
if (cpu->env.features[FEAT_1_EDX] & CPUID_APIC || smp_cpus > 1) {
|
2013-04-05 16:36:54 +02:00
|
|
|
x86_cpu_apic_create(cpu, &local_err);
|
2013-01-16 03:41:47 +01:00
|
|
|
if (local_err != NULL) {
|
2013-04-05 16:36:53 +02:00
|
|
|
goto out;
|
2012-10-13 22:35:39 +02:00
|
|
|
}
|
|
|
|
}
|
2012-07-23 15:22:28 +02:00
|
|
|
#endif
|
|
|
|
|
2012-05-09 23:15:32 +02:00
|
|
|
mce_init(cpu);
|
2013-07-27 02:53:25 +02:00
|
|
|
qemu_init_vcpu(cs);
|
2013-04-05 16:36:54 +02:00
|
|
|
|
2014-10-21 17:00:45 +02:00
|
|
|
/* Only Intel CPUs support hyperthreading. Even though QEMU fixes this
|
|
|
|
* issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX
|
|
|
|
* based on inputs (sockets,cores,threads), it is still better to gives
|
|
|
|
* users a warning.
|
|
|
|
*
|
|
|
|
* NOTE: the following code has to follow qemu_init_vcpu(). Otherwise
|
|
|
|
* cs->nr_threads hasn't be populated yet and the checking is incorrect.
|
|
|
|
*/
|
|
|
|
if (!IS_INTEL_CPU(env) && cs->nr_threads > 1 && !ht_warned) {
|
|
|
|
error_report("AMD CPU doesn't support hyperthreading. Please configure"
|
|
|
|
" -smp options properly.");
|
|
|
|
ht_warned = true;
|
|
|
|
}
|
|
|
|
|
2013-04-05 16:36:54 +02:00
|
|
|
x86_cpu_apic_realize(cpu, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
goto out;
|
|
|
|
}
|
2013-07-27 02:53:25 +02:00
|
|
|
cpu_reset(cs);
|
2013-01-16 03:41:47 +01:00
|
|
|
|
2013-04-05 16:36:53 +02:00
|
|
|
xcc->parent_realize(dev, &local_err);
|
|
|
|
out:
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2012-05-09 23:15:32 +02:00
|
|
|
}
|
|
|
|
|
2013-01-22 21:25:09 +01:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2013-01-22 21:25:04 +01:00
|
|
|
/* 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)
|
|
|
|
{
|
2013-01-22 21:25:09 +01:00
|
|
|
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;
|
|
|
|
}
|
2013-01-22 21:25:04 +01:00
|
|
|
}
|
|
|
|
|
2012-04-03 00:00:17 +02:00
|
|
|
static void x86_cpu_initfn(Object *obj)
|
|
|
|
{
|
2012-12-17 06:18:02 +01:00
|
|
|
CPUState *cs = CPU(obj);
|
2012-04-03 00:00:17 +02:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
2014-02-10 11:21:30 +01:00
|
|
|
X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
|
2012-04-03 00:00:17 +02:00
|
|
|
CPUX86State *env = &cpu->env;
|
2012-06-19 15:39:46 +02:00
|
|
|
static int inited;
|
2012-04-03 00:00:17 +02:00
|
|
|
|
2013-01-17 12:13:41 +01:00
|
|
|
cs->env_ptr = env;
|
2012-04-03 00:00:17 +02:00
|
|
|
cpu_exec_init(env);
|
2012-04-17 12:10:29 +02:00
|
|
|
|
|
|
|
object_property_add(obj, "family", "int",
|
2012-04-17 14:42:22 +02:00
|
|
|
x86_cpuid_version_get_family,
|
2012-04-17 12:10:29 +02:00
|
|
|
x86_cpuid_version_set_family, NULL, NULL, NULL);
|
2012-04-17 12:16:39 +02:00
|
|
|
object_property_add(obj, "model", "int",
|
2012-04-17 14:48:14 +02:00
|
|
|
x86_cpuid_version_get_model,
|
2012-04-17 12:16:39 +02:00
|
|
|
x86_cpuid_version_set_model, NULL, NULL, NULL);
|
2012-04-17 14:14:18 +02:00
|
|
|
object_property_add(obj, "stepping", "int",
|
2012-04-17 14:50:53 +02:00
|
|
|
x86_cpuid_version_get_stepping,
|
2012-04-17 14:14:18 +02:00
|
|
|
x86_cpuid_version_set_stepping, NULL, NULL, NULL);
|
2012-04-17 18:41:40 +02:00
|
|
|
object_property_add(obj, "level", "int",
|
|
|
|
x86_cpuid_get_level,
|
|
|
|
x86_cpuid_set_level, NULL, NULL, NULL);
|
2012-04-17 18:44:07 +02:00
|
|
|
object_property_add(obj, "xlevel", "int",
|
|
|
|
x86_cpuid_get_xlevel,
|
|
|
|
x86_cpuid_set_xlevel, NULL, NULL, NULL);
|
2012-04-17 19:22:58 +02:00
|
|
|
object_property_add_str(obj, "vendor",
|
|
|
|
x86_cpuid_get_vendor,
|
|
|
|
x86_cpuid_set_vendor, NULL);
|
2012-04-17 15:17:27 +02:00
|
|
|
object_property_add_str(obj, "model-id",
|
2012-04-17 23:02:26 +02:00
|
|
|
x86_cpuid_get_model_id,
|
2012-04-17 15:17:27 +02:00
|
|
|
x86_cpuid_set_model_id, NULL);
|
2012-04-18 00:12:23 +02:00
|
|
|
object_property_add(obj, "tsc-frequency", "int",
|
|
|
|
x86_cpuid_get_tsc_freq,
|
|
|
|
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
|
2013-04-25 16:05:26 +02:00
|
|
|
object_property_add(obj, "apic-id", "int",
|
|
|
|
x86_cpuid_get_apic_id,
|
|
|
|
x86_cpuid_set_apic_id, NULL, NULL, NULL);
|
2013-05-06 18:20:07 +02:00
|
|
|
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
|
|
|
|
x86_cpu_get_feature_words,
|
2013-05-06 18:20:09 +02:00
|
|
|
NULL, NULL, (void *)env->features, NULL);
|
|
|
|
object_property_add(obj, "filtered-features", "X86CPUFeatureWordInfo",
|
|
|
|
x86_cpu_get_feature_words,
|
|
|
|
NULL, NULL, (void *)cpu->filtered_features, NULL);
|
2012-04-17 12:10:29 +02:00
|
|
|
|
2013-06-05 15:18:40 +02:00
|
|
|
cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
|
2013-01-22 21:25:04 +01:00
|
|
|
env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
|
2012-06-19 15:39:46 +02:00
|
|
|
|
2014-02-10 11:21:30 +01:00
|
|
|
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
|
|
|
|
|
2012-06-19 15:39:46 +02:00
|
|
|
/* init various static tables used in TCG mode */
|
|
|
|
if (tcg_enabled() && !inited) {
|
|
|
|
inited = 1;
|
|
|
|
optimize_flags_init();
|
|
|
|
}
|
2012-04-03 00:00:17 +02:00
|
|
|
}
|
|
|
|
|
2013-04-23 10:29:41 +02:00
|
|
|
static int64_t x86_cpu_get_arch_id(CPUState *cs)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
|
|
|
|
return env->cpuid_apic_id;
|
|
|
|
}
|
|
|
|
|
2013-05-28 13:28:38 +02:00
|
|
|
static bool x86_cpu_get_paging_enabled(const CPUState *cs)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
|
|
|
return cpu->env.cr[0] & CR0_PG_MASK;
|
|
|
|
}
|
|
|
|
|
2013-06-21 19:09:18 +02:00
|
|
|
static void x86_cpu_set_pc(CPUState *cs, vaddr value)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
|
|
|
cpu->env.eip = value;
|
|
|
|
}
|
|
|
|
|
2013-06-28 19:31:32 +02:00
|
|
|
static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
|
|
|
cpu->env.eip = tb->pc - tb->cs_base;
|
|
|
|
}
|
|
|
|
|
2013-08-25 18:53:55 +02:00
|
|
|
static bool x86_cpu_has_work(CPUState *cs)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
|
2014-11-11 13:14:05 +01:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
if (cs->interrupt_request & CPU_INTERRUPT_POLL) {
|
|
|
|
apic_poll_irq(cpu->apic_state);
|
|
|
|
cpu_reset_interrupt(cs, CPU_INTERRUPT_POLL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
|
2013-08-25 18:53:55 +02:00
|
|
|
(env->eflags & IF_MASK)) ||
|
|
|
|
(cs->interrupt_request & (CPU_INTERRUPT_NMI |
|
|
|
|
CPU_INTERRUPT_INIT |
|
|
|
|
CPU_INTERRUPT_SIPI |
|
|
|
|
CPU_INTERRUPT_MCE));
|
|
|
|
}
|
|
|
|
|
2013-07-26 22:09:36 +02:00
|
|
|
static Property x86_cpu_properties[] = {
|
|
|
|
DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
|
2013-06-04 15:05:25 +02:00
|
|
|
{ .name = "hv-spinlocks", .info = &qdev_prop_spinlocks },
|
2012-08-08 13:52:51 +02:00
|
|
|
DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
|
2012-08-08 13:54:27 +02:00
|
|
|
DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
|
2014-01-23 14:40:49 +01:00
|
|
|
DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
|
2013-06-04 15:13:14 +02:00
|
|
|
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
|
|
|
|
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
|
2014-06-02 19:28:50 +02:00
|
|
|
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
|
2013-07-26 22:09:36 +02:00
|
|
|
DEFINE_PROP_END_OF_LIST()
|
|
|
|
};
|
|
|
|
|
2012-04-02 23:20:08 +02:00
|
|
|
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
|
|
|
CPUClass *cc = CPU_CLASS(oc);
|
2013-01-16 03:41:47 +01:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
|
|
|
|
|
|
xcc->parent_realize = dc->realize;
|
|
|
|
dc->realize = x86_cpu_realizefn;
|
2013-04-29 18:54:13 +02:00
|
|
|
dc->bus_type = TYPE_ICC_BUS;
|
2013-07-26 22:09:36 +02:00
|
|
|
dc->props = x86_cpu_properties;
|
2012-04-02 23:20:08 +02:00
|
|
|
|
|
|
|
xcc->parent_reset = cc->reset;
|
|
|
|
cc->reset = x86_cpu_reset;
|
2013-06-16 07:49:48 +02:00
|
|
|
cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP;
|
2013-02-02 13:38:08 +01:00
|
|
|
|
2014-02-10 22:02:44 +01:00
|
|
|
cc->class_by_name = x86_cpu_class_by_name;
|
2014-03-03 23:19:19 +01:00
|
|
|
cc->parse_features = x86_cpu_parse_featurestr;
|
2013-08-25 18:53:55 +02:00
|
|
|
cc->has_work = x86_cpu_has_work;
|
2013-02-02 10:57:51 +01:00
|
|
|
cc->do_interrupt = x86_cpu_do_interrupt;
|
2014-09-13 18:45:33 +02:00
|
|
|
cc->cpu_exec_interrupt = x86_cpu_exec_interrupt;
|
2013-05-27 01:33:50 +02:00
|
|
|
cc->dump_state = x86_cpu_dump_state;
|
2013-06-21 19:09:18 +02:00
|
|
|
cc->set_pc = x86_cpu_set_pc;
|
2013-06-28 19:31:32 +02:00
|
|
|
cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
|
2013-06-29 04:18:45 +02:00
|
|
|
cc->gdb_read_register = x86_cpu_gdb_read_register;
|
|
|
|
cc->gdb_write_register = x86_cpu_gdb_write_register;
|
2013-05-28 13:28:38 +02:00
|
|
|
cc->get_arch_id = x86_cpu_get_arch_id;
|
|
|
|
cc->get_paging_enabled = x86_cpu_get_paging_enabled;
|
2013-08-26 03:01:33 +02:00
|
|
|
#ifdef CONFIG_USER_ONLY
|
|
|
|
cc->handle_mmu_fault = x86_cpu_handle_mmu_fault;
|
|
|
|
#else
|
2013-05-28 13:52:01 +02:00
|
|
|
cc->get_memory_mapping = x86_cpu_get_memory_mapping;
|
2013-06-29 18:55:54 +02:00
|
|
|
cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
|
2013-04-19 16:45:06 +02:00
|
|
|
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;
|
|
|
|
cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
|
2013-06-29 18:55:54 +02:00
|
|
|
cc->vmsd = &vmstate_x86_cpu;
|
2013-04-19 16:45:06 +02:00
|
|
|
#endif
|
2013-06-28 23:18:47 +02:00
|
|
|
cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25;
|
2014-09-12 15:06:48 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
cc->debug_excp_handler = breakpoint_handler;
|
|
|
|
#endif
|
2014-09-13 18:45:14 +02:00
|
|
|
cc->cpu_exec_enter = x86_cpu_exec_enter;
|
|
|
|
cc->cpu_exec_exit = x86_cpu_exec_exit;
|
2012-04-02 23:20:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo x86_cpu_type_info = {
|
|
|
|
.name = TYPE_X86_CPU,
|
|
|
|
.parent = TYPE_CPU,
|
|
|
|
.instance_size = sizeof(X86CPU),
|
2012-04-03 00:00:17 +02:00
|
|
|
.instance_init = x86_cpu_initfn,
|
2014-02-10 11:21:30 +01:00
|
|
|
.abstract = true,
|
2012-04-02 23:20:08 +02:00
|
|
|
.class_size = sizeof(X86CPUClass),
|
|
|
|
.class_init = x86_cpu_common_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void x86_cpu_register_types(void)
|
|
|
|
{
|
2014-02-10 11:21:30 +01:00
|
|
|
int i;
|
|
|
|
|
2012-04-02 23:20:08 +02:00
|
|
|
type_register_static(&x86_cpu_type_info);
|
2014-02-10 11:21:30 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
|
|
|
x86_register_cpudef_type(&builtin_x86_defs[i]);
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
type_register_static(&host_x86_cpu_type_info);
|
|
|
|
#endif
|
2012-04-02 23:20:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type_init(x86_cpu_register_types)
|