From patchwork Mon Dec 21 06:46:36 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: john cooper X-Patchwork-Id: 41518 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C90EFB6F07 for ; Mon, 21 Dec 2009 18:13:45 +1100 (EST) Received: from localhost ([127.0.0.1]:56283 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NMcSb-0001P4-Qo for incoming@patchwork.ozlabs.org; Mon, 21 Dec 2009 02:13:41 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NMcRz-0001OZ-Hn for qemu-devel@nongnu.org; Mon, 21 Dec 2009 02:13:03 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NMcRv-0001Nz-HZ for qemu-devel@nongnu.org; Mon, 21 Dec 2009 02:13:03 -0500 Received: from [199.232.76.173] (port=34143 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NMcRv-0001Nw-ED for qemu-devel@nongnu.org; Mon, 21 Dec 2009 02:12:59 -0500 Received: from mx1.redhat.com ([209.132.183.28]:63763) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NMcRu-0003XH-Ts for qemu-devel@nongnu.org; Mon, 21 Dec 2009 02:12:59 -0500 Received: from int-mx03.intmail.prod.int.phx2.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id nBL7Cuwk012421 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 21 Dec 2009 02:12:57 -0500 Received: from anvil.naka.net (pilototp-int.redhat.com [10.11.232.41]) by int-mx03.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id nBL7CnQO027335; Mon, 21 Dec 2009 02:12:51 -0500 Message-ID: <4B2F19CC.5020808@redhat.com> Date: Mon, 21 Dec 2009 01:46:36 -0500 From: john cooper User-Agent: Thunderbird 2.0.0.9 (X11/20071115) MIME-Version: 1.0 To: KVM list X-Scanned-By: MIMEDefang 2.67 on 10.5.11.16 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: john.cooper@redhat.com, qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH] Add definitions for current cpu models.. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This adds definitions for contemporary processors which may be selected via -cpu , as an alternative to the existing use of -cpu qemu64 augmented with a series of feature flags. The primary motivation was determination of a least common denominator within a given processor class for simplification of guest migration. It is still possible to modify an arbitrary model via additional feature flags however the goal here was to make doing so unnecessary in typical usage. The other consideration was providing models names reflective of current processors. Both AMD and Intel have reviewed the models in terms of balancing generality of migration vs. excessive feature downgrade relative to released silicon. A cpu feature 'check' option is also added which warns when feature flags (either implicit in a cpu model or explicit on the command line) would have otherwise been quietly disabled for a guest. This patch was tested relative to qemu-kvm.git. Signed-off-by: john cooper diff --git a/target-i386/helper.c b/target-i386/helper.c index 9a50da6..a706cae 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -44,7 +44,7 @@ static const char *feature_name[] = { static const char *ext_feature_name[] = { "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est", "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, - NULL, NULL, "dca", NULL, NULL, "x2apic", NULL, "popcnt", + NULL, NULL, "dca", "sse4.1", "sse4.2", "x2apic", NULL, "popcnt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "hypervisor", }; static const char *ext2_feature_name[] = { @@ -60,6 +60,18 @@ static const char *ext3_feature_name[] = { 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; + static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features, uint32_t *ext_features, uint32_t *ext2_features, @@ -171,6 +183,139 @@ static x86_def_t x86_defs[] = { .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor" }, { + .name = "Merom", + .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, + .family = 6, /* P6 */ + .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, /* from qemu64 */ + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, + .ext3_features = CPUID_EXT3_SVM, /* from qemu64 */ + .xlevel = 0x8000000A, + .model_id = "Intel Merom Core 2", + }, + { + .name = "Penryn", + .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, + .family = 6, /* P6 */ + .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_SSSE3 | CPUID_EXT_SSE41, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, + .ext3_features = CPUID_EXT3_SVM, + .xlevel = 0x8000000A, + .model_id = "Intel Penryn Core 2", + }, + { + .name = "Nehalem", + .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, + .family = 6, /* P6 */ + .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_SSSE3 | CPUID_EXT_SSE41 | + CPUID_EXT_SSE42 | CPUID_EXT_POPCNT, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, + .ext3_features = CPUID_EXT3_SVM, + .xlevel = 0x8000000A, + .model_id = "Intel Nehalem Core i7", + }, + { + .name = "Opteron_G1", + .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, + .family = 15, + .model = 6, + .stepping = 1, + .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_MONITOR, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, + .ext3_features = CPUID_EXT3_SVM, + .xlevel = 0x80000008, + .model_id = "AMD Opteron G1", + }, + { + .name = "Opteron_G2", + .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, + .family = 15, + .model = 6, + .stepping = 1, + .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 | CPUID_EXT_CX16, + .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | + CPUID_EXT2_RDTSCP, + .ext3_features = CPUID_EXT3_SVM, + .xlevel = 0x80000008, + .model_id = "AMD Opteron G2", + }, + { + .name = "Opteron_G3", + .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, + .family = 15, + .model = 6, + .stepping = 1, + .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 | CPUID_EXT_CX16, + .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_POPCNT, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | + CPUID_EXT2_RDTSCP, + .ext3_features = CPUID_EXT3_SVM | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | + CPUID_EXT3_MISALIGNSSE, + .xlevel = 0x80000008, + .model_id = "AMD Opteron G3", + }, + /* this feature is needed for Solaris and isn't fully implemented */ + { .name = "core2duo", .level = 10, .family = 6, @@ -319,7 +464,7 @@ static x86_def_t x86_defs[] = { /* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */ .xlevel = 0x8000000A, .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz", - }, + } }; static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, @@ -370,6 +515,51 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def) 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; @@ -473,6 +663,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) fprintf(stderr, "unrecognized feature %s\n", featurestr); goto error; } + } else if (!strcmp(featurestr, "check")) { + check_cpuid = 1; } else { fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); goto error; @@ -487,6 +679,9 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) x86_cpu_def->ext_features &= ~minus_ext_features; x86_cpu_def->ext2_features &= ~minus_ext2_features; x86_cpu_def->ext3_features &= ~minus_ext3_features; + if (check_cpuid) + check_features_against_host(x86_cpu_def); + free(s); return 0;