From aa87d45855c7b255b451622a84a3e5b9b4393425 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 17 Jan 2013 18:59:28 -0200 Subject: target-i386: Don't set any KVM flag by default if KVM is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a cleanup that tries to solve two small issues: - We don't need a separate kvm_pv_eoi_features variable just to keep a constant calculated at compile-time, and this style would require adding a separate variable (that's declared twice because of the CONFIG_KVM ifdef) for each feature that's going to be enabled/disabled by machine-type compat code. - The pc-1.3 code is setting the kvm_pv_eoi flag on cpuid_kvm_features even when KVM is disabled at runtime. This small inconsistency in the cpuid_kvm_features field isn't a problem today because cpuid_kvm_features is ignored by the TCG code, but it may cause unexpected problems later when refactoring the CPUID handling code. This patch eliminates the kvm_pv_eoi_features variable and simply uses kvm_enabled() inside the enable_kvm_pv_eoi() compat function, so it enables kvm_pv_eoi only if KVM is enabled. I believe this makes the behavior of enable_kvm_pv_eoi() clearer and easier to understand. Signed-off-by: Eduardo Habkost Acked-by: Gleb Natapov Reviewed-by: Marcelo Tosatti Signed-off-by: Andreas Färber --- target-i386/cpu.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 376d4c8737..ac2ec243e1 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -206,22 +206,16 @@ typedef struct model_features_t { int check_cpuid = 0; int enforce_cpuid = 0; -#if defined(CONFIG_KVM) static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) | (1 << KVM_FEATURE_NOP_IO_DELAY) | (1 << KVM_FEATURE_CLOCKSOURCE2) | (1 << KVM_FEATURE_ASYNC_PF) | (1 << KVM_FEATURE_STEAL_TIME) | (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT); -static const uint32_t kvm_pv_eoi_features = (0x1 << KVM_FEATURE_PV_EOI); -#else -static uint32_t kvm_default_features = 0; -static const uint32_t kvm_pv_eoi_features = 0; -#endif void enable_kvm_pv_eoi(void) { - kvm_default_features |= kvm_pv_eoi_features; + kvm_default_features |= (1UL << KVM_FEATURE_PV_EOI); } void host_cpuid(uint32_t function, uint32_t count, @@ -1602,7 +1596,9 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) goto out; } - def->kvm_features |= kvm_default_features; + if (kvm_enabled()) { + def->kvm_features |= kvm_default_features; + } def->ext_features |= CPUID_EXT_HYPERVISOR; if (cpu_x86_parse_featurestr(def, features) < 0) { -- cgit v1.2.3 From 2969475869a6f33b8883c2fbf90252dcf617902e Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 17 Jan 2013 18:59:29 -0200 Subject: pc: Reverse pc_init_pci() compatibility logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the pc-1.4 machine init function enables PV EOI and then calls the pc-1.2 machine init function. The problem with this approach is that now we can't enable any additional compatibility code inside the pc-1.2 init function because it would end up enabling the compatibility behavior on pc-1.3 and pc-1.4 as well. This reverses the logic so that the pc-1.2 machine init function will disable PV EOI, and then call the pc-1.4 machine init function. This way we can change older machine-types to enable compatibility behavior, and the newer machine-types (pc-1.3, pc-q35-1.4 and pc-i440fx-1.4) would just use the default behavior. (This means that one nice side-effect of this change is that pc-q35-1.4 will get PV EOI enabled by default, too) It would be interesting to eventually change pc_init_pci_no_kvmclock() and pc_init_isa() to reuse pc_init_pci_1_2() as well (so we don't need to duplicate compatibility code on those two functions). But this will be probably much easier to do after we create a PCInitArgs struct for the PC initialization arguments, and/or after we use global-properties to implement the compatibility modes present in pc_init_pci_1_2(). Signed-off-by: Eduardo Habkost Acked-by: Michael S. Tsirkin Reviewed-by: Marcelo Tosatti Signed-off-by: Andreas Färber --- target-i386/cpu.c | 5 +++-- target-i386/cpu.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index ac2ec243e1..db9086e7ce 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -211,11 +211,12 @@ static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) | (1 << KVM_FEATURE_CLOCKSOURCE2) | (1 << KVM_FEATURE_ASYNC_PF) | (1 << KVM_FEATURE_STEAL_TIME) | + (1 << KVM_FEATURE_PV_EOI) | (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT); -void enable_kvm_pv_eoi(void) +void disable_kvm_pv_eoi(void) { - kvm_default_features |= (1UL << KVM_FEATURE_PV_EOI); + kvm_default_features &= ~(1UL << KVM_FEATURE_PV_EOI); } void host_cpuid(uint32_t function, uint32_t count, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 4e091cdec3..9d4fcf93b6 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1250,7 +1250,7 @@ void do_smm_enter(CPUX86State *env1); void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); -void enable_kvm_pv_eoi(void); +void disable_kvm_pv_eoi(void); /* Return name of 32-bit register, from a R_* constant */ const char *get_register_name_32(unsigned int reg); -- cgit v1.2.3 From b164e48ed1600055bc190aa3ab42c18004d2c711 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:01 -0200 Subject: kvm: Create kvm_arch_vcpu_id() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow each architecture to define how the VCPU ID is set on the KVM_CREATE_VCPU ioctl call. Signed-off-by: Eduardo Habkost Acked-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/kvm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'target-i386') diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 3acff40c47..5f3f7894c1 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -411,6 +411,11 @@ static void cpu_update_state(void *opaque, int running, RunState state) } } +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + int kvm_arch_init_vcpu(CPUState *cs) { struct { -- cgit v1.2.3 From 83b17af5e619abdf11721826b08fa4f30e9dc4ee Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:02 -0200 Subject: target-i386: kvm: Set vcpu_id to APIC ID instead of CPU index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPU ID in KVM is supposed to be the APIC ID, so change the KVM_CREATE_VCPU call to match it. The current behavior didn't break anything yet because today the APIC ID is assumed to be equal to the CPU index, but this won't be true in the future. Signed-off-by: Eduardo Habkost Reviewed-by: Marcelo Tosatti Acked-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/kvm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'target-i386') diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5f3f7894c1..c440809cb2 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -411,9 +411,10 @@ static void cpu_update_state(void *opaque, int running, RunState state) } } -unsigned long kvm_arch_vcpu_id(CPUState *cpu) +unsigned long kvm_arch_vcpu_id(CPUState *cs) { - return cpu->cpu_index; + X86CPU *cpu = X86_CPU(cs); + return cpu->env.cpuid_apic_id; } int kvm_arch_init_vcpu(CPUState *cs) -- cgit v1.2.3 From cb41bad3c2c7d82405cbe057c944ed4fd176d82a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:04 -0200 Subject: target-i386: Introduce x86_cpu_apic_id_from_index() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function will be used by both the CPU initialization code and the fw_cfg table initialization code. Later this function will be updated to generate APIC IDs according to the CPU topology. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 17 ++++++++++++++++- target-i386/cpu.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index db9086e7ce..75dc973e3b 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2194,6 +2194,21 @@ void x86_cpu_realize(Object *obj, Error **errp) cpu_reset(CPU(cpu)); } +/* 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) +{ + /* right now APIC ID == CPU index. this will eventually change to use + * the CPU topology configuration properly + */ + return cpu_index; +} + static void x86_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); @@ -2228,7 +2243,7 @@ static void x86_cpu_initfn(Object *obj) x86_cpuid_get_tsc_freq, x86_cpuid_set_tsc_freq, NULL, NULL, NULL); - env->cpuid_apic_id = cs->cpu_index; + env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index); /* init various static tables used in TCG mode */ if (tcg_enabled() && !inited) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9d4fcf93b6..9442f08305 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1255,4 +1255,6 @@ void disable_kvm_pv_eoi(void); /* Return name of 32-bit register, from a R_* constant */ const char *get_register_name_32(unsigned int reg); +uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index); + #endif /* CPU_I386_H */ -- cgit v1.2.3 From 247c9de13f9d54a94734875000a9faea8168c8ca Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 23 Jan 2013 15:58:27 -0200 Subject: target-i386: Topology & APIC ID utility functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces utility functions for the APIC ID calculation, based on: Intel® 64 Architecture Processor Topology Enumeration http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ The code should be compatible with AMD's "Extended Method" described at: AMD CPUID Specification (Publication #25481) Section 3: Multiple Core Calcuation as long as: - nr_threads is set to 1; - OFFSET_IDX is assumed to be 0; - CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). Unit tests included. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/topology.h | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 target-i386/topology.h (limited to 'target-i386') diff --git a/target-i386/topology.h b/target-i386/topology.h new file mode 100644 index 0000000000..24ed525453 --- /dev/null +++ b/target-i386/topology.h @@ -0,0 +1,136 @@ +/* + * x86 CPU topology data structures and functions + * + * Copyright (c) 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef TARGET_I386_TOPOLOGY_H +#define TARGET_I386_TOPOLOGY_H + +/* This file implements the APIC-ID-based CPU topology enumeration logic, + * documented at the following document: + * Intel® 64 Architecture Processor Topology Enumeration + * http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ + * + * This code should be compatible with AMD's "Extended Method" described at: + * AMD CPUID Specification (Publication #25481) + * Section 3: Multiple Core Calcuation + * as long as: + * nr_threads is set to 1; + * OFFSET_IDX is assumed to be 0; + * CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). + */ + +#include +#include + +#include "qemu/bitops.h" + +/* APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support + */ +typedef uint32_t apic_id_t; + +/* Return the bit width needed for 'count' IDs + */ +static unsigned apicid_bitwidth_for_count(unsigned count) +{ + g_assert(count >= 1); + if (count == 1) { + return 0; + } + return bitops_flsl(count - 1) + 1; +} + +/* Bit width of the SMT_ID (thread ID) field on the APIC ID + */ +static inline unsigned apicid_smt_width(unsigned nr_cores, unsigned nr_threads) +{ + return apicid_bitwidth_for_count(nr_threads); +} + +/* Bit width of the Core_ID field + */ +static inline unsigned apicid_core_width(unsigned nr_cores, unsigned nr_threads) +{ + return apicid_bitwidth_for_count(nr_cores); +} + +/* Bit offset of the Core_ID field + */ +static inline unsigned apicid_core_offset(unsigned nr_cores, + unsigned nr_threads) +{ + return apicid_smt_width(nr_cores, nr_threads); +} + +/* Bit offset of the Pkg_ID (socket ID) field + */ +static inline unsigned apicid_pkg_offset(unsigned nr_cores, unsigned nr_threads) +{ + return apicid_core_offset(nr_cores, nr_threads) + + apicid_core_width(nr_cores, nr_threads); +} + +/* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID + * + * The caller must make sure core_id < nr_cores and smt_id < nr_threads. + */ +static inline apic_id_t apicid_from_topo_ids(unsigned nr_cores, + unsigned nr_threads, + unsigned pkg_id, + unsigned core_id, + unsigned smt_id) +{ + return (pkg_id << apicid_pkg_offset(nr_cores, nr_threads)) | + (core_id << apicid_core_offset(nr_cores, nr_threads)) | + smt_id; +} + +/* Calculate thread/core/package IDs for a specific topology, + * based on (contiguous) CPU index + */ +static inline void x86_topo_ids_from_idx(unsigned nr_cores, + unsigned nr_threads, + unsigned cpu_index, + unsigned *pkg_id, + unsigned *core_id, + unsigned *smt_id) +{ + unsigned core_index = cpu_index / nr_threads; + *smt_id = cpu_index % nr_threads; + *core_id = core_index % nr_cores; + *pkg_id = core_index / nr_cores; +} + +/* Make APIC ID for the CPU 'cpu_index' + * + * 'cpu_index' is a sequential, contiguous ID for the CPU. + */ +static inline apic_id_t x86_apicid_from_cpu_idx(unsigned nr_cores, + unsigned nr_threads, + unsigned cpu_index) +{ + unsigned pkg_id, core_id, smt_id; + x86_topo_ids_from_idx(nr_cores, nr_threads, cpu_index, + &pkg_id, &core_id, &smt_id); + return apicid_from_topo_ids(nr_cores, nr_threads, pkg_id, core_id, smt_id); +} + +#endif /* TARGET_I386_TOPOLOGY_H */ -- cgit v1.2.3 From 8932cfdf7b95734c9b4a114b8ed0b4527af77ce7 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:09 -0200 Subject: pc: Generate APIC IDs according to CPU topology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This keeps compatibility on machine-types pc-1.2 and older, and prints a warning in case the requested configuration won't get the correct topology. I couldn't think of a better way to warn about broken topology when in compat mode other than using error_report(). The warning message will probably be buried in a log file somewhere, but it's better than nothing. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 28 ++++++++++++++++++++++++---- target-i386/cpu.h | 1 + 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 75dc973e3b..c5acaa7523 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -23,6 +23,8 @@ #include "cpu.h" #include "sysemu/kvm.h" +#include "sysemu/cpus.h" +#include "topology.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -2194,6 +2196,14 @@ void x86_cpu_realize(Object *obj, Error **errp) cpu_reset(CPU(cpu)); } +/* Enables contiguous-apic-ID mode, for compatibility */ +static bool compat_apic_id_mode; + +void enable_compat_apic_id_mode(void) +{ + compat_apic_id_mode = true; +} + /* Calculates initial APIC ID for a specific CPU index * * Currently we need to be able to calculate the APIC ID from the CPU index @@ -2203,10 +2213,20 @@ void x86_cpu_realize(Object *obj, Error **errp) */ uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index) { - /* right now APIC ID == CPU index. this will eventually change to use - * the CPU topology configuration properly - */ - return cpu_index; + uint32_t correct_id; + static bool warned; + + correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index); + if (compat_apic_id_mode) { + if (cpu_index != correct_id && !warned) { + error_report("APIC IDs set in compatibility mode, " + "CPU topology won't match the configuration"); + warned = true; + } + return cpu_index; + } else { + return correct_id; + } } static void x86_cpu_initfn(Object *obj) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9442f08305..27efe59488 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1256,5 +1256,6 @@ void disable_kvm_pv_eoi(void); const char *get_register_name_32(unsigned int reg); uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index); +void enable_compat_apic_id_mode(void); #endif /* CPU_I386_H */ -- cgit v1.2.3 From 4bfe910d4728807e7d80de152a7ef33dd608033f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 01:00:24 +0100 Subject: target-i386: Simplify cpu_x86_find_by_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catch NULL name argument early to avoid repeated checks. Similarly, check for -cpu host early and untangle from iterating through model definitions. This prepares for introducing X86CPU subclasses. Signed-off-by: Andreas Färber --- target-i386/cpu.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index c5acaa7523..37a4b03887 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1318,20 +1318,22 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) { x86_def_t *def; - for (def = x86_defs; def; def = def->next) { - if (name && !strcmp(name, def->name)) { - break; - } + if (name == NULL) { + return -1; } - if (kvm_enabled() && name && strcmp(name, "host") == 0) { + if (kvm_enabled() && strcmp(name, "host") == 0) { kvm_cpu_fill_host(x86_cpu_def); - } else if (!def) { - return -1; - } else { - memcpy(x86_cpu_def, def, sizeof(*def)); + return 0; } - return 0; + for (def = x86_defs; def; def = def->next) { + if (strcmp(name, def->name) == 0) { + memcpy(x86_cpu_def, def, sizeof(*def)); + return 0; + } + } + + return -1; } /* Parse "+feature,-feature,feature=foo" CPU feature string -- cgit v1.2.3 From 7fc9b714eb4877ca83ce8e437ec93d34fca0eb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 01:02:28 +0100 Subject: target-i386: Drop redundant list of CPU definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is no longer needed since dropping cpudef config file support. Cleaning this up removes knowledge about other models from x86_def_t, in preparation for reusing x86_def_t as intermediate step towards pure QOM X86CPU subclasses. Signed-off-by: Andreas Färber --- target-i386/cpu.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 37a4b03887..df974d7ede 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -335,7 +335,6 @@ static void add_flagname_to_bitmaps(const char *flagname, } typedef struct x86_def_t { - struct x86_def_t *next; const char *name; uint32_t level; uint32_t vendor1, vendor2, vendor3; @@ -393,11 +392,7 @@ typedef struct x86_def_t { #define TCG_SVM_FEATURES 0 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP) -/* maintains list of cpu model definitions - */ -static x86_def_t *x86_defs = {NULL}; - -/* built-in cpu model definitions (deprecated) +/* built-in CPU model definitions */ static x86_def_t builtin_x86_defs[] = { { @@ -1317,6 +1312,7 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque, static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) { x86_def_t *def; + int i; if (name == NULL) { return -1; @@ -1326,7 +1322,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) return 0; } - for (def = x86_defs; def; def = def->next) { + for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { + def = &builtin_x86_defs[i]; if (strcmp(name, def->name) == 0) { memcpy(x86_cpu_def, def, sizeof(*def)); return 0; @@ -1512,8 +1509,10 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf) { x86_def_t *def; char buf[256]; + int i; - for (def = x86_defs; def; def = def->next) { + for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { + def = &builtin_x86_defs[i]; snprintf(buf, sizeof(buf), "%s", def->name); (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id); } @@ -1535,11 +1534,13 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) { CpuDefinitionInfoList *cpu_list = NULL; x86_def_t *def; + int i; - for (def = x86_defs; def; def = def->next) { + for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { CpuDefinitionInfoList *entry; CpuDefinitionInfo *info; + def = &builtin_x86_defs[i]; info = g_malloc0(sizeof(*info)); info->name = g_strdup(def->name); @@ -1662,7 +1663,6 @@ void x86_cpudef_setup(void) for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) { x86_def_t *def = &builtin_x86_defs[i]; - def->next = x86_defs; /* Look for specific "cpudef" models that */ /* have the QEMU version in .model_id */ @@ -1675,8 +1675,6 @@ void x86_cpudef_setup(void) break; } } - - x86_defs = def; } } -- cgit v1.2.3 From 8ba8a69848f8b910207a4b57c68db9a7e92af578 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:35 +0100 Subject: target-i386: Print deprecation warning if xlevel < 0x80000000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index df974d7ede..b75ea9fc8f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1395,6 +1395,8 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) goto error; } if (numvalue < 0x80000000) { + fprintf(stderr, "xlevel value shall always be >= 0x80000000" + ", fixup will be removed in future versions\n"); numvalue += 0x80000000; } x86_cpu_def->xlevel = numvalue; -- cgit v1.2.3 From 99b88a1708919934f4092f7b6dcc2cca9d4072e9 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:36 +0100 Subject: target-i386: Replace uint32_t vendor fields by vendor string in x86_def_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vendor property setter takes string as vendor value but cpudefs use uint32_t vendor[123] fields to define vendor value. It makes it difficult to unify and use property setter for values from cpudefs. Simplify code by using vendor property setter, vendor[123] fields are converted into vendor[13] array to keep its value. And vendor property setter is used to access/set value on CPU. - Make for() cycle reusable for the next patch by adding x86_cpu_vendor_words2str() Intel's CPUID spec[1] says: " 5.1.1 ... These registers contain the ASCII string: GenuineIntel ... " List[2] of known vendor values shows that they all are 12 ASCII characters long, padded where necessary with space. Current supported values are all ASCII characters packed in ebx, edx, ecx. So lets state that QEMU supports 12 printable ASCII characters packed in ebx, edx, ecx registers for cpuid(0) instruction. *1 - http://www.intel.com/Assets/PDF/appnote/241618.pdf *2 - http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 147 ++++++++++++++++-------------------------------------- target-i386/cpu.h | 6 +-- 2 files changed, 47 insertions(+), 106 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b75ea9fc8f..043a21dcd7 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -47,6 +47,18 @@ #include "hw/apic_internal.h" #endif +static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + uint32_t vendor2, uint32_t vendor3) +{ + int i; + for (i = 0; i < 4; i++) { + dst[i] = vendor1 >> (8 * i); + dst[i + 4] = vendor2 >> (8 * i); + dst[i + 8] = vendor3 >> (8 * i); + } + dst[CPUID_VENDOR_SZ] = '\0'; +} + /* feature flags taken from "Intel Processor Identification and the CPUID * Instruction" and AMD's "CPUID Specification". In cases of disagreement * between feature naming conventions, aliases may be added. @@ -337,7 +349,8 @@ static void add_flagname_to_bitmaps(const char *flagname, typedef struct x86_def_t { const char *name; uint32_t level; - uint32_t vendor1, vendor2, vendor3; + /* vendor is zero-terminated, 12 character ASCII string */ + char vendor[CPUID_VENDOR_SZ + 1]; int family; int model; int stepping; @@ -398,9 +411,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "qemu64", .level = 4, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 6, .model = 2, .stepping = 3, @@ -417,9 +428,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "phenom", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 16, .model = 2, .stepping = 3, @@ -445,9 +454,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "core2duo", .level = 10, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 15, .stepping = 11, @@ -466,9 +473,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "kvm64", .level = 5, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 15, .model = 6, .stepping = 1, @@ -492,9 +497,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "qemu32", .level = 4, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 3, .stepping = 3, @@ -505,9 +508,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "kvm32", .level = 5, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 15, .model = 6, .stepping = 1, @@ -522,9 +523,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "coreduo", .level = 10, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 14, .stepping = 8, @@ -540,9 +539,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "486", .level = 1, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 4, .model = 0, .stepping = 0, @@ -552,9 +549,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium", .level = 1, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 5, .model = 4, .stepping = 3, @@ -564,9 +559,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium2", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 5, .stepping = 2, @@ -576,9 +569,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium3", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 7, .stepping = 3, @@ -588,9 +579,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "athlon", .level = 2, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 6, .model = 2, .stepping = 3, @@ -604,9 +593,7 @@ static x86_def_t builtin_x86_defs[] = { .name = "n270", /* original is on level 10 */ .level = 5, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 28, .stepping = 2, @@ -625,9 +612,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Conroe", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 2, .stepping = 3, @@ -645,9 +630,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Penryn", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 2, .stepping = 3, @@ -666,9 +649,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Nehalem", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 2, .stepping = 3, @@ -687,9 +668,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Westmere", .level = 11, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 44, .stepping = 1, @@ -709,9 +688,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "SandyBridge", .level = 0xd, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 42, .stepping = 1, @@ -734,9 +711,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Haswell", .level = 0xd, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 60, .stepping = 1, @@ -764,9 +739,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G1", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 15, .model = 6, .stepping = 1, @@ -788,9 +761,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G2", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 15, .model = 6, .stepping = 1, @@ -814,9 +785,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G3", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 15, .model = 6, .stepping = 1, @@ -842,9 +811,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G4", .level = 0xd, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 21, .model = 1, .stepping = 2, @@ -874,9 +841,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G5", .level = 0xd, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 21, .model = 2, .stepping = 0, @@ -937,9 +902,7 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) x86_cpu_def->name = "host"; host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); - x86_cpu_def->vendor1 = ebx; - x86_cpu_def->vendor2 = edx; - x86_cpu_def->vendor3 = ecx; + x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx); host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); @@ -967,9 +930,7 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) x86_cpu_def->vendor_override = 0; /* Call Centaur's CPUID instruction. */ - if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 && - x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 && - x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) { + if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) { host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx); eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); if (eax >= 0xC0000001) { @@ -1205,15 +1166,10 @@ static char *x86_cpuid_get_vendor(Object *obj, Error **errp) X86CPU *cpu = X86_CPU(obj); CPUX86State *env = &cpu->env; char *value; - int i; value = (char *)g_malloc(CPUID_VENDOR_SZ + 1); - for (i = 0; i < 4; i++) { - value[i ] = env->cpuid_vendor1 >> (8 * i); - value[i + 4] = env->cpuid_vendor2 >> (8 * i); - value[i + 8] = env->cpuid_vendor3 >> (8 * i); - } - value[CPUID_VENDOR_SZ] = '\0'; + x86_cpu_vendor_words2str(value, env->cpuid_vendor1, env->cpuid_vendor2, + env->cpuid_vendor3); return value; } @@ -1337,7 +1293,6 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) */ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) { - unsigned int i; char *featurestr; /* Single 'key=value" string being parsed */ /* Features to be added */ FeatureWordArray plus_features = { 0 }; @@ -1401,18 +1356,7 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } 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); - } + pstrcpy(x86_cpu_def->vendor, sizeof(x86_cpu_def->vendor), val); x86_cpu_def->vendor_override = 1; } else if (!strcmp(featurestr, "model_id")) { pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), @@ -1613,10 +1557,7 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) error_setg(&error, "Invalid cpu_model string format: %s", cpu_model); goto out; } - assert(def->vendor1); - env->cpuid_vendor1 = def->vendor1; - env->cpuid_vendor2 = def->vendor2; - env->cpuid_vendor3 = def->vendor3; + object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error); env->cpuid_vendor_override = def->vendor_override; object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 27efe59488..3833e6f019 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -537,14 +537,14 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */ #define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */ #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */ +#define CPUID_VENDOR_INTEL "GenuineIntel" #define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */ #define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */ #define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */ +#define CPUID_VENDOR_AMD "AuthenticAMD" -#define CPUID_VENDOR_VIA_1 0x746e6543 /* "Cent" */ -#define CPUID_VENDOR_VIA_2 0x48727561 /* "aurH" */ -#define CPUID_VENDOR_VIA_3 0x736c7561 /* "auls" */ +#define CPUID_VENDOR_VIA "CentaurHauls" #define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */ -- cgit v1.2.3 From 11acfdd5a1647895ff9094e7f93f3317224eb4d8 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:37 +0100 Subject: target-i386: Remove vendor_override field from CPUX86State MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 8935499831312 makes cpuid return to guest host's vendor value instead of built-in one by default if kvm_enabled() == true and allows to override this behavior if 'vendor' is specified on -cpu command line. But every time guest calls cpuid to get 'vendor' value, host's value is read again and again in default case. It complicates semantics of vendor property and makes it harder to use. Instead of reading 'vendor' value from host every time cpuid[vendor] is called, override 'vendor' value only once in cpu_x86_find_by_name(), when built-in CPU model is found and if(kvm_enabled() == true). It provides the same default semantics if (kvm_enabled() == true) vendor = host's vendor else vendor = built-in vendor and then later: if (custom vendor) vendor = custom vendor 'vendor' value is overridden when user provides it on -cpu command line, and there is no need for vendor_override field anymore, remove it. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 27 ++++++++++++--------------- target-i386/cpu.h | 1 - 2 files changed, 12 insertions(+), 16 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 043a21dcd7..b11fe30f37 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -359,7 +359,6 @@ typedef struct x86_def_t { uint32_t kvm_features, svm_features; uint32_t xlevel; char model_id[48]; - int vendor_override; /* Store the results of Centaur's CPUID instructions */ uint32_t ext4_features; uint32_t xlevel2; @@ -927,7 +926,6 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX); cpu_x86_fill_model_id(x86_cpu_def->model_id); - x86_cpu_def->vendor_override = 0; /* Call Centaur's CPUID instruction. */ if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) { @@ -1194,7 +1192,6 @@ static void x86_cpuid_set_vendor(Object *obj, const char *value, env->cpuid_vendor2 |= ((uint8_t)value[i + 4]) << (8 * i); env->cpuid_vendor3 |= ((uint8_t)value[i + 8]) << (8 * i); } - env->cpuid_vendor_override = 1; } static char *x86_cpuid_get_model_id(Object *obj, Error **errp) @@ -1282,6 +1279,18 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) def = &builtin_x86_defs[i]; if (strcmp(name, def->name) == 0) { memcpy(x86_cpu_def, def, sizeof(*def)); + /* sysenter isn't supported in compatibility mode on AMD, + * syscall isn't supported in compatibility mode on Intel. + * Normally we advertise the actual CPU vendor, but you can + * override this using the 'vendor' property if you want to use + * KVM's sysenter/syscall emulation in compatibility mode and + * when doing cross vendor migration + */ + if (kvm_enabled()) { + uint32_t ebx = 0, ecx = 0, edx = 0; + host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx); + } return 0; } } @@ -1357,7 +1366,6 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) x86_cpu_def->xlevel = numvalue; } else if (!strcmp(featurestr, "vendor")) { pstrcpy(x86_cpu_def->vendor, sizeof(x86_cpu_def->vendor), val); - 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); @@ -1558,7 +1566,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) goto out; } object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error); - env->cpuid_vendor_override = def->vendor_override; object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); object_property_set_int(OBJECT(cpu), def->model, "model", &error); @@ -1627,16 +1634,6 @@ static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx, *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, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 3833e6f019..62508dc688 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -835,7 +835,6 @@ typedef struct CPUX86State { uint32_t cpuid_ext2_features; uint32_t cpuid_ext3_features; uint32_t cpuid_apic_id; - int cpuid_vendor_override; /* Store the results of Centaur's CPUID instructions */ uint32_t cpuid_xlevel2; uint32_t cpuid_ext4_features; -- cgit v1.2.3 From a91987c25db38834091174681a6e1ffcbe582182 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:38 +0100 Subject: target-i386: Set custom features/properties without intermediate x86_def_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move custom features parsing after built-in cpu_model defaults are set and set custom features directly on CPU instance. That allows to make a clear distinction between built-in cpu model defaults that eventually should go into class_init() and extra property setting which is done after defaults are set on CPU instance. Impl. details: * use object_property_parse() property setter so it would be a mechanical change to switch to global properties later. * And after all current features/properties are converted into static properties, it will take a trivial patch to switch to global properties. Which will allow to: * get CPU instance initialized with all parameters passed on -cpu ... cmd. line from object_new() call. * call cpu_model/featurestr parsing only once before CPUs are created * open a road for removing CPUxxxState.cpu_model_str field, when other CPUs are similarly converted to subclasses and static properties. - re-factor error handling, to use Error instead of fprintf()s, since it is anyway passed in for property setter. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 118 +++++++++++++++++++++++------------------------------- 1 file changed, 51 insertions(+), 67 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b11fe30f37..117b8b02db 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1300,7 +1300,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) /* Parse "+feature,-feature,feature=foo" CPU feature string */ -static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) +static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) { char *featurestr; /* Single 'key=value" string being parsed */ /* Features to be added */ @@ -1308,6 +1308,7 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) /* Features to be removed */ FeatureWordArray minus_features = { 0 }; uint32_t numvalue; + CPUX86State *env = &cpu->env; featurestr = features ? strtok(features, ",") : NULL; @@ -1320,77 +1321,57 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } else if ((val = strchr(featurestr, '='))) { *val = 0; val++; if (!strcmp(featurestr, "family")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err || numvalue > 0xff + 0xf) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->family = numvalue; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "model")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err || numvalue > 0xff) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->model = numvalue; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "stepping")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err || numvalue > 0xf) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->stepping = numvalue ; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "level")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->level = numvalue; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "xlevel")) { char *err; + char num[32]; + numvalue = strtoul(val, &err, 0); if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; + error_setg(errp, "bad numerical value %s\n", val); + goto out; } if (numvalue < 0x80000000) { fprintf(stderr, "xlevel value shall always be >= 0x80000000" ", fixup will be removed in future versions\n"); numvalue += 0x80000000; } - x86_cpu_def->xlevel = numvalue; + snprintf(num, sizeof(num), "%" PRIu32, numvalue); + object_property_parse(OBJECT(cpu), num, featurestr, errp); } else if (!strcmp(featurestr, "vendor")) { - pstrcpy(x86_cpu_def->vendor, sizeof(x86_cpu_def->vendor), val); + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "model_id")) { - pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), - val); + object_property_parse(OBJECT(cpu), val, "model-id", errp); } else if (!strcmp(featurestr, "tsc_freq")) { int64_t tsc_freq; char *err; + char num[32]; tsc_freq = strtosz_suffix_unit(val, &err, STRTOSZ_DEFSUFFIX_B, 1000); if (tsc_freq < 0 || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; + error_setg(errp, "bad numerical value %s\n", val); + goto out; } - x86_cpu_def->tsc_khz = tsc_freq / 1000; + snprintf(num, sizeof(num), "%" PRId64, tsc_freq); + object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp); } else if (!strcmp(featurestr, "hv_spinlocks")) { char *err; numvalue = strtoul(val, &err, 0); if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; + error_setg(errp, "bad numerical value %s\n", val); + goto out; } hyperv_set_spinlock_retries(numvalue); } else { - fprintf(stderr, "unrecognized feature %s\n", featurestr); - goto error; + error_setg(errp, "unrecognized feature %s\n", featurestr); + goto out; } } else if (!strcmp(featurestr, "check")) { check_cpuid = 1; @@ -1401,31 +1382,34 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } else if (!strcmp(featurestr, "hv_vapic")) { hyperv_enable_vapic_recommended(true); } else { - fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); - goto error; + error_setg(errp, "feature string `%s' not in format (+feature|" + "-feature|feature=xyz)\n", featurestr); + goto out; + } + if (error_is_set(errp)) { + goto out; } featurestr = strtok(NULL, ","); } - x86_cpu_def->features |= plus_features[FEAT_1_EDX]; - x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX]; - x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX]; - x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX]; - x86_cpu_def->ext4_features |= plus_features[FEAT_C000_0001_EDX]; - x86_cpu_def->kvm_features |= plus_features[FEAT_KVM]; - x86_cpu_def->svm_features |= plus_features[FEAT_SVM]; - x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; - x86_cpu_def->features &= ~minus_features[FEAT_1_EDX]; - x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX]; - x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; - x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; - x86_cpu_def->ext4_features &= ~minus_features[FEAT_C000_0001_EDX]; - x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM]; - x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM]; - x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; - return 0; + env->cpuid_features |= plus_features[FEAT_1_EDX]; + env->cpuid_ext_features |= plus_features[FEAT_1_ECX]; + env->cpuid_ext2_features |= plus_features[FEAT_8000_0001_EDX]; + env->cpuid_ext3_features |= plus_features[FEAT_8000_0001_ECX]; + env->cpuid_ext4_features |= plus_features[FEAT_C000_0001_EDX]; + env->cpuid_kvm_features |= plus_features[FEAT_KVM]; + env->cpuid_svm_features |= plus_features[FEAT_SVM]; + env->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; + env->cpuid_features &= ~minus_features[FEAT_1_EDX]; + env->cpuid_ext_features &= ~minus_features[FEAT_1_ECX]; + env->cpuid_ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; + env->cpuid_ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; + env->cpuid_ext4_features &= ~minus_features[FEAT_C000_0001_EDX]; + env->cpuid_kvm_features &= ~minus_features[FEAT_KVM]; + env->cpuid_svm_features &= ~minus_features[FEAT_SVM]; + env->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; -error: - return -1; +out: + return; } /* generate a composite string into buf of all cpuid names in featureset @@ -1561,10 +1545,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) } def->ext_features |= CPUID_EXT_HYPERVISOR; - if (cpu_x86_parse_featurestr(def, features) < 0) { - error_setg(&error, "Invalid cpu_model string format: %s", cpu_model); - goto out; - } object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error); object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); @@ -1584,7 +1564,11 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) "tsc-frequency", &error); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); + if (error) { + goto out; + } + cpu_x86_parse_featurestr(cpu, features, &error); out: g_strfreev(model_pieces); if (error) { -- cgit v1.2.3 From 2c728dfef56d468a6a80b4dacdfb7109220d2546 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:39 +0100 Subject: target-i386: Remove setting tsc-frequency from x86_def_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting tsc-frequency from x86_def_t is NOP because default tsc_khz in x86_def_t is 0 and CPUX86State.tsc_khz is also initialized to 0 by default. So there is no need to overwrite tsc_khz with default 0 because field was already initialized to 0. Custom tsc-frequency setting is not affected due to it being set without using x86_def_t. Field tsc_khz in x86_def_t becomes unused with this patch, so drop it as well. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'target-i386') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 117b8b02db..5c108e17ab 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -354,7 +354,6 @@ typedef struct x86_def_t { int family; int model; int stepping; - int tsc_khz; uint32_t features, ext_features, ext2_features, ext3_features; uint32_t kvm_features, svm_features; uint32_t xlevel; @@ -1560,8 +1559,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) env->cpuid_ext4_features = def->ext4_features; env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features; env->cpuid_xlevel2 = def->xlevel2; - object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000, - "tsc-frequency", &error); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); if (error) { -- cgit v1.2.3