aboutsummaryrefslogtreecommitdiff
path: root/target-i386/helper.c
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@amd.com>2010-03-11 14:38:55 +0100
committerAurelien Jarno <aurelien@aurel32.net>2010-03-13 16:50:54 +0100
commitc6dc6f63bf7ee418c0a430a8b3386817ede69940 (patch)
tree908804c8272af5f1f6ee6539336337da52aa9fdc /target-i386/helper.c
parenta6c6f76ceb95a0986fd1a36cc30f8241734d20c3 (diff)
x86/cpuid: move CPUID functions into separate file
about half of target-i386/helper.c consist of CPUID related functions. Only one of them is a real TCG helper function. So move the whole CPUID stuff out of this into a separate file to get better maintainable parts. This is only code reordering and should not affect QEMU's functionality. Signed-off-by: Andre Przywara <andre.przywara@amd.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target-i386/helper.c')
-rw-r--r--target-i386/helper.c1112
1 files changed, 0 insertions, 1112 deletions
diff --git a/target-i386/helper.c b/target-i386/helper.c
index f109d5a97e..05758f9bfe 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -29,875 +29,6 @@
#include "kvm.h"
//#define DEBUG_MMU
-#include "qemu-option.h"
-#include "qemu-config.h"
-
-/* 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[] = {
- "pni|sse3" /* Intel,AMD sse3 */, NULL, NULL, "monitor",
- "ds_cpl", "vmx", NULL /* Linux smx */, "est",
- "tm2", "ssse3", "cid", NULL,
- NULL, "cx16", "xtpr", NULL,
- NULL, NULL, "dca", "sse4.1|sse4_1",
- "sse4.2|sse4_2", "x2apic", NULL, "popcnt",
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "hypervisor",
-};
-static const char *ext2_feature_name[] = {
- "fpu", "vme", "de", "pse",
- "tsc", "msr", "pae", "mce",
- "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
- "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", NULL, NULL /* Linux mp */,
- "nx" /* Intel xd */, NULL, "mmxext", "mmx",
- "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp",
- NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
-};
-static const char *ext3_feature_name[] = {
- "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
- "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
- "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL,
- "skinit", "wdt", NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
-};
-
-static const char *kvm_feature_name[] = {
- "kvmclock", "kvm_nopiodelay", "kvm_mmu", 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, NULL,
-};
-
-/* collects per-function cpuid data
- */
-typedef struct model_features_t {
- uint32_t *guest_feat;
- uint32_t *host_feat;
- uint32_t check_feat;
- const char **flag_names;
- uint32_t cpuid;
- } model_features_t;
-
-int check_cpuid = 0;
-int enforce_cpuid = 0;
-
-static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
- uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
-
-#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.
- */
-static int sstrcmp(const char *s1, const char *e1, const char *s2,
- const char *e2)
-{
- 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
- * *pval and return success, otherwise return zero
- */
-static int lookup_feature(uint32_t *pval, const char *s, const char *e,
- const char **featureset)
-{
- uint32_t mask;
- const char **ppc;
-
- for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
- if (*ppc && !altcmp(s, e, *ppc)) {
- *pval |= mask;
- break;
- }
- return (mask ? 1 : 0);
-}
-
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
- uint32_t *ext_features,
- uint32_t *ext2_features,
- uint32_t *ext3_features,
- uint32_t *kvm_features)
-{
- if (!lookup_feature(features, flagname, NULL, feature_name) &&
- !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
- !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
- !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
- !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name))
- fprintf(stderr, "CPU feature %s not found\n", flagname);
-}
-
-typedef struct x86_def_t {
- struct x86_def_t *next;
- const char *name;
- uint32_t level;
- uint32_t vendor1, vendor2, vendor3;
- int family;
- int model;
- int stepping;
- uint32_t features, ext_features, ext2_features, ext3_features, kvm_features;
- uint32_t xlevel;
- char model_id[48];
- int vendor_override;
- uint32_t flags;
-} x86_def_t;
-
-#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)
-
-/* maintains list of cpu model definitions
- */
-static x86_def_t *x86_defs = {NULL};
-
-/* built-in cpu model definitions (deprecated)
- */
-static x86_def_t builtin_x86_defs[] = {
-#ifdef TARGET_X86_64
- {
- .name = "qemu64",
- .level = 4,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
- .family = 6,
- .model = 2,
- .stepping = 3,
- .features = PPRO_FEATURES |
- /* these features are needed for Win64 and aren't fully implemented */
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- /* this feature is needed for Solaris and isn't fully implemented */
- CPUID_PSE36,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
- CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
- .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
- CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
- .xlevel = 0x8000000A,
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
- },
- {
- .name = "phenom",
- .level = 5,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
- .family = 16,
- .model = 2,
- .stepping = 3,
- /* Missing: CPUID_VME, CPUID_HT */
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- CPUID_PSE36,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
- CPUID_EXT_POPCNT,
- /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
- CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
- CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
- CPUID_EXT2_FFXSR,
- /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
- CPUID_EXT3_CR8LEG,
- CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
- CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
- .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
- CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
- .xlevel = 0x8000001A,
- .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
- },
- {
- .name = "core2duo",
- .level = 10,
- .family = 6,
- .model = 15,
- .stepping = 11,
- /* The original CPU also implements these features:
- CPUID_VME, CPUID_DTS, CPUID_ACPI, CPUID_SS, CPUID_HT,
- CPUID_TM, CPUID_PBE */
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- CPUID_PSE36,
- /* The original CPU also implements these ext features:
- CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST,
- CPUID_EXT_TM2, CPUID_EXT_CX16, CPUID_EXT_XTPR, CPUID_EXT_PDCM */
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3,
- .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
- .ext3_features = CPUID_EXT3_LAHF_LM,
- .xlevel = 0x80000008,
- .model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz",
- },
- {
- .name = "kvm64",
- .level = 5,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
- .family = 15,
- .model = 6,
- .stepping = 1,
- /* Missing: CPUID_VME, CPUID_HT */
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- CPUID_PSE36,
- /* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
- /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
- 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 */
- .ext3_features = 0,
- .xlevel = 0x80000008,
- .model_id = "Common KVM processor"
- },
-#endif
- {
- .name = "qemu32",
- .level = 4,
- .family = 6,
- .model = 3,
- .stepping = 3,
- .features = PPRO_FEATURES,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
- .xlevel = 0,
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
- },
- {
- .name = "coreduo",
- .level = 10,
- .family = 6,
- .model = 14,
- .stepping = 8,
- /* The original CPU also implements these features:
- CPUID_DTS, CPUID_ACPI, CPUID_SS, CPUID_HT,
- CPUID_TM, CPUID_PBE */
- .features = PPRO_FEATURES | CPUID_VME |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA,
- /* The original CPU also implements these ext features:
- CPUID_EXT_VMX, CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_XTPR,
- CPUID_EXT_PDCM */
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR,
- .ext2_features = CPUID_EXT2_NX,
- .xlevel = 0x80000008,
- .model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz",
- },
- {
- .name = "486",
- .level = 0,
- .family = 4,
- .model = 0,
- .stepping = 0,
- .features = I486_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "pentium",
- .level = 1,
- .family = 5,
- .model = 4,
- .stepping = 3,
- .features = PENTIUM_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "pentium2",
- .level = 2,
- .family = 6,
- .model = 5,
- .stepping = 2,
- .features = PENTIUM2_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "pentium3",
- .level = 2,
- .family = 6,
- .model = 7,
- .stepping = 3,
- .features = PENTIUM3_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "athlon",
- .level = 2,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
- .family = 6,
- .model = 2,
- .stepping = 3,
- .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
- .xlevel = 0x80000008,
- /* XXX: put another string ? */
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
- },
- {
- .name = "n270",
- /* original is on level 10 */
- .level = 5,
- .family = 6,
- .model = 28,
- .stepping = 2,
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME,
- /* Missing: CPUID_DTS | CPUID_ACPI | CPUID_SS |
- * CPUID_HT | CPUID_TM | CPUID_PBE */
- /* Some CPUs got no CPUID_SEP */
- .ext_features = CPUID_EXT_MONITOR |
- CPUID_EXT_SSE3 /* PNI */ | CPUID_EXT_SSSE3,
- /* Missing: CPUID_EXT_DSCPL | CPUID_EXT_EST |
- * CPUID_EXT_TM2 | CPUID_EXT_XTPR */
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_NX,
- /* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */
- .xlevel = 0x8000000A,
- .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz",
- },
-};
-
-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;
-}
-
-static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
-{
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
-
- x86_cpu_def->name = "host";
- host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->level = eax;
- x86_cpu_def->vendor1 = ebx;
- x86_cpu_def->vendor2 = edx;
- x86_cpu_def->vendor3 = ecx;
-
- host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
- x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
- x86_cpu_def->stepping = eax & 0x0F;
- x86_cpu_def->ext_features = ecx;
- x86_cpu_def->features = edx;
-
- host_cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->xlevel = eax;
-
- host_cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->ext2_features = edx;
- x86_cpu_def->ext3_features = ecx;
- cpu_x86_fill_model_id(x86_cpu_def->model_id);
- x86_cpu_def->vendor_override = 0;
-
- return 0;
-}
-
-static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
-{
- int i;
-
- for (i = 0; i < 32; ++i)
- if (1 << i & mask) {
- fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
- " flag '%s' [0x%08x]\n",
- f->cpuid >> 16, f->cpuid & 0xffff,
- f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
- break;
- }
- return 0;
-}
-
-/* best effort attempt to inform user requested cpu flags aren't making
- * their way to the guest. Note: ft[].check_feat ideally should be
- * specified via a guest_def field to suppress report of extraneous flags.
- */
-static int check_features_against_host(x86_def_t *guest_def)
-{
- x86_def_t host_def;
- uint32_t mask;
- int rv, i;
- struct model_features_t ft[] = {
- {&guest_def->features, &host_def.features,
- ~0, feature_name, 0x00000000},
- {&guest_def->ext_features, &host_def.ext_features,
- ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
- {&guest_def->ext2_features, &host_def.ext2_features,
- ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
- {&guest_def->ext3_features, &host_def.ext3_features,
- ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
-
- cpu_x86_fill_host(&host_def);
- for (rv = 0, i = 0; i < sizeof (ft) / sizeof (ft[0]); ++i)
- for (mask = 1; mask; mask <<= 1)
- if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
- !(*ft[i].host_feat & mask)) {
- unavailable_host_feature(&ft[i], mask);
- rv = 1;
- }
- return rv;
-}
-
-static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
-{
- unsigned int i;
- x86_def_t *def;
-
- char *s = strdup(cpu_model);
- char *featurestr, *name = strtok(s, ",");
- uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0, plus_kvm_features = 0;
- uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0, minus_kvm_features = 0;
- uint32_t numvalue;
-
- for (def = x86_defs; def; def = def->next)
- if (!strcmp(name, def->name))
- break;
- if (kvm_enabled() && strcmp(name, "host") == 0) {
- cpu_x86_fill_host(x86_cpu_def);
- } else if (!def) {
- goto error;
- } else {
- memcpy(x86_cpu_def, def, sizeof(*def));
- }
-
- plus_kvm_features = ~0; /* not supported bits will be filtered out later */
-
- add_flagname_to_bitmaps("hypervisor", &plus_features,
- &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
- &plus_kvm_features);
-
- featurestr = strtok(NULL, ",");
-
- while (featurestr) {
- char *val;
- if (featurestr[0] == '+') {
- add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features, &plus_kvm_features);
- } else if (featurestr[0] == '-') {
- add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features, &minus_kvm_features);
- } else if ((val = strchr(featurestr, '='))) {
- *val = 0; val++;
- if (!strcmp(featurestr, "family")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->family = numvalue;
- } else if (!strcmp(featurestr, "model")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err || numvalue > 0xff) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->model = numvalue;
- } else if (!strcmp(featurestr, "stepping")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err || numvalue > 0xf) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->stepping = numvalue ;
- } else if (!strcmp(featurestr, "level")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->level = numvalue;
- } else if (!strcmp(featurestr, "xlevel")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- if (numvalue < 0x80000000) {
- numvalue += 0x80000000;
- }
- x86_cpu_def->xlevel = numvalue;
- } else if (!strcmp(featurestr, "vendor")) {
- if (strlen(val) != 12) {
- fprintf(stderr, "vendor string must be 12 chars long\n");
- goto error;
- }
- x86_cpu_def->vendor1 = 0;
- x86_cpu_def->vendor2 = 0;
- x86_cpu_def->vendor3 = 0;
- for(i = 0; i < 4; i++) {
- x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i);
- x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i);
- x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i);
- }
- x86_cpu_def->vendor_override = 1;
- } else if (!strcmp(featurestr, "model_id")) {
- pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
- val);
- } else {
- fprintf(stderr, "unrecognized feature %s\n", featurestr);
- goto error;
- }
- } else if (!strcmp(featurestr, "check")) {
- check_cpuid = 1;
- } else if (!strcmp(featurestr, "enforce")) {
- check_cpuid = enforce_cpuid = 1;
- } else {
- fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
- goto error;
- }
- featurestr = strtok(NULL, ",");
- }
- x86_cpu_def->features |= plus_features;
- x86_cpu_def->ext_features |= plus_ext_features;
- x86_cpu_def->ext2_features |= plus_ext2_features;
- x86_cpu_def->ext3_features |= plus_ext3_features;
- x86_cpu_def->kvm_features |= plus_kvm_features;
- x86_cpu_def->features &= ~minus_features;
- x86_cpu_def->ext_features &= ~minus_ext_features;
- x86_cpu_def->ext2_features &= ~minus_ext2_features;
- x86_cpu_def->ext3_features &= ~minus_ext3_features;
- x86_cpu_def->kvm_features &= ~minus_kvm_features;
- if (check_cpuid) {
- if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
- goto error;
- }
- free(s);
- return 0;
-
-error:
- free(s);
- return -1;
-}
-
-/* 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,
- const char **featureset, uint32_t flags)
-{
- 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;
- }
-}
-
-/* generate CPU information:
- * -? list model names
- * -?model list model names/IDs
- * -?dump output all model (x86_def_t) data
- * -?cpuid list all recognized cpuid flag names
- */
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
- const char *optarg)
-{
- unsigned char model = !strcmp("?model", optarg);
- unsigned char dump = !strcmp("?dump", optarg);
- unsigned char cpuid = !strcmp("?cpuid", optarg);
- x86_def_t *def;
- char buf[256];
-
- if (cpuid) {
- (*cpu_fprintf)(f, "Recognized CPUID flags:\n");
- listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
- (*cpu_fprintf)(f, " f_edx: %s\n", buf);
- listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
- (*cpu_fprintf)(f, " f_ecx: %s\n", buf);
- listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
- (*cpu_fprintf)(f, " extf_edx: %s\n", buf);
- listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
- (*cpu_fprintf)(f, " extf_ecx: %s\n", buf);
- return;
- }
- for (def = x86_defs; def; def = def->next) {
- snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
- if (model || dump) {
- (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
- } else {
- (*cpu_fprintf)(f, "x86 %16s\n", buf);
- }
- if (dump) {
- memcpy(buf, &def->vendor1, sizeof (def->vendor1));
- memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
- memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
- buf[12] = '\0';
- (*cpu_fprintf)(f,
- " family %d model %d stepping %d level %d xlevel 0x%x"
- " vendor \"%s\"\n",
- def->family, def->model, def->stepping, def->level,
- def->xlevel, buf);
- listflags(buf, sizeof (buf), def->features, feature_name, 0);
- (*cpu_fprintf)(f, " feature_edx %08x (%s)\n", def->features,
- buf);
- listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
- 0);
- (*cpu_fprintf)(f, " feature_ecx %08x (%s)\n", def->ext_features,
- buf);
- listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
- 0);
- (*cpu_fprintf)(f, " extfeature_edx %08x (%s)\n",
- def->ext2_features, buf);
- listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
- 0);
- (*cpu_fprintf)(f, " extfeature_ecx %08x (%s)\n",
- def->ext3_features, buf);
- (*cpu_fprintf)(f, "\n");
- }
- }
-}
-
-static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
-{
- x86_def_t def1, *def = &def1;
-
- if (cpu_x86_find_by_name(def, cpu_model) < 0)
- return -1;
- if (def->vendor1) {
- env->cpuid_vendor1 = def->vendor1;
- env->cpuid_vendor2 = def->vendor2;
- env->cpuid_vendor3 = def->vendor3;
- } else {
- env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1;
- env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2;
- env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3;
- }
- env->cpuid_vendor_override = def->vendor_override;
- env->cpuid_level = def->level;
- if (def->family > 0x0f)
- env->cpuid_version = 0xf00 | ((def->family - 0x0f) << 20);
- else
- env->cpuid_version = def->family << 8;
- env->cpuid_version |= ((def->model & 0xf) << 4) | ((def->model >> 4) << 16);
- env->cpuid_version |= def->stepping;
- env->cpuid_features = def->features;
- env->pat = 0x0007040600070406ULL;
- env->cpuid_ext_features = def->ext_features;
- env->cpuid_ext2_features = def->ext2_features;
- env->cpuid_xlevel = def->xlevel;
- env->cpuid_kvm_features = def->kvm_features;
- {
- const char *model_id = def->model_id;
- int c, len, i;
- if (!model_id)
- model_id = "";
- len = strlen(model_id);
- 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));
- }
- }
- return 0;
-}
-
-#if !defined(CONFIG_USER_ONLY)
-/* copy vendor id string to 32 bit register, nul pad as needed
- */
-static void cpyid(const char *s, uint32_t *id)
-{
- char *d = (char *)id;
- char i;
-
- for (i = sizeof (*id); i--; )
- *d++ = *s ? *s++ : '\0';
-}
-
-/* interpret radix and convert from string to arbitrary scalar,
- * otherwise flag failure
- */
-#define setscalar(pval, str, perr) \
-{ \
- char *pend; \
- unsigned long ul; \
- \
- ul = strtoul(str, &pend, 0); \
- *str && !*pend ? (*pval = ul) : (*perr = 1); \
-}
-
-/* map cpuid options to feature bits, otherwise return failure
- * (option tags in *str are delimited by whitespace)
- */
-static void setfeatures(uint32_t *pval, const char *str,
- const char **featureset, int *perr)
-{
- const char *p, *q;
-
- for (q = p = str; *p || *q; q = p) {
- while (iswhite(*p))
- q = ++p;
- while (*p && !iswhite(*p))
- ++p;
- if (!*q && !*p)
- return;
- if (!lookup_feature(pval, q, p, featureset)) {
- fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
- (int)(p - q), q);
- *perr = 1;
- return;
- }
- }
-}
-
-/* map config file options to x86_def_t form
- */
-static int cpudef_setfield(const char *name, const char *str, void *opaque)
-{
- x86_def_t *def = opaque;
- int err = 0;
-
- if (!strcmp(name, "name")) {
- def->name = strdup(str);
- } else if (!strcmp(name, "model_id")) {
- strncpy(def->model_id, str, sizeof (def->model_id));
- } else if (!strcmp(name, "level")) {
- setscalar(&def->level, str, &err)
- } else if (!strcmp(name, "vendor")) {
- cpyid(&str[0], &def->vendor1);
- cpyid(&str[4], &def->vendor2);
- cpyid(&str[8], &def->vendor3);
- } else if (!strcmp(name, "family")) {
- setscalar(&def->family, str, &err)
- } else if (!strcmp(name, "model")) {
- setscalar(&def->model, str, &err)
- } else if (!strcmp(name, "stepping")) {
- setscalar(&def->stepping, str, &err)
- } else if (!strcmp(name, "feature_edx")) {
- setfeatures(&def->features, str, feature_name, &err);
- } else if (!strcmp(name, "feature_ecx")) {
- setfeatures(&def->ext_features, str, ext_feature_name, &err);
- } else if (!strcmp(name, "extfeature_edx")) {
- setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
- } else if (!strcmp(name, "extfeature_ecx")) {
- setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
- } else if (!strcmp(name, "xlevel")) {
- setscalar(&def->xlevel, str, &err)
- } else {
- fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
- return (1);
- }
- if (err) {
- fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
- return (1);
- }
- return (0);
-}
-
-/* register config file entry as x86_def_t
- */
-static int cpudef_register(QemuOpts *opts, void *opaque)
-{
- x86_def_t *def = qemu_mallocz(sizeof (x86_def_t));
-
- qemu_opt_foreach(opts, cpudef_setfield, def, 1);
- def->next = x86_defs;
- x86_defs = def;
- return (0);
-}
-#endif /* !CONFIG_USER_ONLY */
-
-/* register "cpudef" models defined in configuration file. Here we first
- * preload any built-in definitions
- */
-void x86_cpudef_setup(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
- builtin_x86_defs[i].next = x86_defs;
- builtin_x86_defs[i].flags = 1;
- x86_defs = &builtin_x86_defs[i];
- }
-#if !defined(CONFIG_USER_ONLY)
- qemu_opts_foreach(&qemu_cpudef_opts, cpudef_register, NULL, 0);
-#endif
-}
/* NOTE: must be called outside the CPU execute loop */
void cpu_reset(CPUX86State *env)
@@ -1954,249 +1085,6 @@ static void mce_init(CPUX86State *cenv)
}
}
-static void host_cpuid(uint32_t function, uint32_t count,
- uint32_t *eax, uint32_t *ebx,
- uint32_t *ecx, uint32_t *edx)
-{
-#if defined(CONFIG_KVM)
- 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");
-#else
- 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");
-#endif
-
- if (eax)
- *eax = vec[0];
- if (ebx)
- *ebx = vec[1];
- if (ecx)
- *ecx = vec[2];
- if (edx)
- *edx = vec[3];
-#endif
-}
-
-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;
-
- /* sysenter isn't supported on compatibility mode on AMD, syscall
- * isn't supported in compatibility mode on Intel.
- * Normally we advertise the actual cpu vendor, but you can override
- * this if you want to use KVM's sysenter/syscall emulation
- * in compatibility mode and when doing cross vendor migration
- */
- if (kvm_enabled() && env->cpuid_vendor_override) {
- host_cpuid(0, 0, NULL, ebx, ecx, edx);
- }
-}
-
-void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
- uint32_t *eax, uint32_t *ebx,
- uint32_t *ecx, uint32_t *edx)
-{
- /* test if maximum index reached */
- if (index & 0x80000000) {
- if (index > env->cpuid_xlevel)
- index = env->cpuid_level;
- } 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. */
- *ecx = env->cpuid_ext_features;
- *edx = env->cpuid_features;
- if (env->nr_cores * env->nr_threads > 1) {
- *ebx |= (env->nr_cores * env->nr_threads) << 16;
- *edx |= 1 << 28; /* HTT bit */
- }
- break;
- case 2:
- /* cache info: needed for Pentium Pro compatibility */
- *eax = 1;
- *ebx = 0;
- *ecx = 0;
- *edx = 0x2c307d;
- break;
- case 4:
- /* cache info: needed for Core compatibility */
- if (env->nr_cores > 1) {
- *eax = (env->nr_cores - 1) << 26;
- } else {
- *eax = 0;
- }
- switch (count) {
- case 0: /* L1 dcache info */
- *eax |= 0x0000121;
- *ebx = 0x1c0003f;
- *ecx = 0x000003f;
- *edx = 0x0000001;
- break;
- case 1: /* L1 icache info */
- *eax |= 0x0000122;
- *ebx = 0x1c0003f;
- *ecx = 0x000003f;
- *edx = 0x0000001;
- break;
- case 2: /* L2 cache info */
- *eax |= 0x0000143;
- if (env->nr_threads > 1) {
- *eax |= (env->nr_threads - 1) << 14;
- }
- *ebx = 0x3c0003f;
- *ecx = 0x0000fff;
- *edx = 0x0000001;
- break;
- default: /* end of info */
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- }
- 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;
- 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 */
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- 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;
- *ecx = env->cpuid_ext3_features;
- *edx = env->cpuid_ext2_features;
-
- /* 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.
- */
- if (env->nr_cores * env->nr_threads > 1) {
- 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 */
- }
- }
-
- if (kvm_enabled()) {
- /* Nested SVM not yet supported in upstream QEMU */
- *ecx &= ~CPUID_EXT3_SVM;
- }
- 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) */
- *eax = 0x01ff01ff;
- *ebx = 0x01ff01ff;
- *ecx = 0x40020140;
- *edx = 0x40020140;
- break;
- case 0x80000006:
- /* cache info (L2 cache) */
- *eax = 0;
- *ebx = 0x42004200;
- *ecx = 0x02008140;
- *edx = 0;
- break;
- case 0x80000008:
- /* virtual & phys address size in low 2 bytes. */
-/* XXX: This value must match the one used in the MMU code. */
- if (env->cpuid_ext2_features & CPUID_EXT2_LM) {
- /* 64 bit processor */
-/* XXX: The physical address space is limited to 42 bits in exec.c. */
- *eax = 0x00003028; /* 48 bits virtual, 40 bits physical */
- } else {
- if (env->cpuid_features & CPUID_PSE36)
- *eax = 0x00000024; /* 36 bits physical */
- else
- *eax = 0x00000020; /* 32 bits physical */
- }
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- if (env->nr_cores * env->nr_threads > 1) {
- *ecx |= (env->nr_cores * env->nr_threads) - 1;
- }
- break;
- case 0x8000000A:
- *eax = 0x00000001; /* SVM Revision */
- *ebx = 0x00000010; /* nr of ASIDs */
- *ecx = 0;
- *edx = 0; /* optional features */
- break;
- default:
- /* reserved values: zero */
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- }
-}
-
-
int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
target_ulong *base, unsigned int *limit,
unsigned int *flags)