diff options
-rw-r--r-- | hw/i386/pc.c | 35 | ||||
-rw-r--r-- | linux-user/main.c | 9 | ||||
-rw-r--r-- | target-i386/cpu-qom.h | 1 | ||||
-rw-r--r-- | target-i386/cpu.c | 146 | ||||
-rw-r--r-- | target-i386/cpu.h | 13 | ||||
-rw-r--r-- | target-i386/kvm.c | 2 | ||||
-rw-r--r-- | target-i386/topology.h (renamed from include/hw/i386/topology.h) | 6 | ||||
-rw-r--r-- | tests/Makefile | 2 | ||||
-rw-r--r-- | tests/test-x86-cpuid.c | 2 |
9 files changed, 113 insertions, 103 deletions
diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d2e07ca981..03dc007d8d 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -25,8 +25,6 @@ #include "hw/i386/pc.h" #include "hw/char/serial.h" #include "hw/i386/apic.h" -#include "hw/i386/topology.h" -#include "sysemu/cpus.h" #include "hw/block/fdc.h" #include "hw/ide.h" #include "hw/pci/pci.h" @@ -631,39 +629,6 @@ bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length) return false; } -/* Enables contiguous-apic-ID mode, for compatibility */ -static bool compat_apic_id_mode; - -void enable_compat_apic_id_mode(void) -{ - compat_apic_id_mode = true; -} - -/* Calculates initial APIC ID for a specific CPU index - * - * Currently we need to be able to calculate the APIC ID from the CPU index - * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have - * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of - * all CPUs up to max_cpus. - */ -uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index) -{ - uint32_t correct_id; - static bool warned; - - correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index); - if (compat_apic_id_mode) { - if (cpu_index != correct_id && !warned) { - error_report("APIC IDs set in compatibility mode, " - "CPU topology won't match the configuration"); - warned = true; - } - return cpu_index; - } else { - return correct_id; - } -} - /* Calculates the limit to CPU APIC ID values * * This function returns the limit for the APIC ID value, so that all diff --git a/linux-user/main.c b/linux-user/main.c index 111c1ffafc..d92702a734 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3453,17 +3453,10 @@ CPUArchState *cpu_copy(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); CPUArchState *new_env = cpu_init(cpu_model); - CPUState *new_cpu; + CPUState *new_cpu = ENV_GET_CPU(new_env); CPUBreakpoint *bp; CPUWatchpoint *wp; - if (!new_env) { - fprintf(stderr, "cpu_copy: Failed to create new CPU\n"); - exit(1); - } - - new_cpu = ENV_GET_CPU(new_env); - /* Reset non arch specific state */ cpu_reset(new_cpu); diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 31a0c1e776..b557b619cf 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -93,7 +93,6 @@ typedef struct X86CPU { bool expose_kvm; bool migratable; bool host_features; - int64_t apic_id; /* if true the CPUID code directly forward host cache leaves to the guest */ bool cache_info_passthrough; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 14c6c4abaf..d543e2b537 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -25,6 +25,7 @@ #include "sysemu/kvm.h" #include "sysemu/cpus.h" #include "kvm_i386.h" +#include "topology.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -1689,7 +1690,7 @@ static void x86_cpuid_get_apic_id(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - int64_t value = cpu->apic_id; + int64_t value = cpu->env.cpuid_apic_id; visit_type_int(v, &value, name, errp); } @@ -1722,11 +1723,11 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque, return; } - if ((value != cpu->apic_id) && cpu_exists(value)) { + if ((value != cpu->env.cpuid_apic_id) && cpu_exists(value)) { error_setg(errp, "CPU with APIC ID %" PRIi64 " exists", value); return; } - cpu->apic_id = value; + cpu->env.cpuid_apic_id = value; } /* Generic getter for "feature-words" and "filtered-features" properties */ @@ -1910,19 +1911,34 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features, } } -/* Print all cpuid feature names in featureset +/* 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(FILE *f, fprintf_function print, const char **featureset) -{ - int bit; - bool first = true; - - for (bit = 0; bit < 32; bit++) { - if (featureset[bit]) { - print(f, "%s%s", first ? "" : " ", featureset[bit]); - first = false; +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. */ @@ -1947,9 +1963,8 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf) for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) { FeatureWordInfo *fw = &feature_word_info[i]; - (*cpu_fprintf)(f, " "); - listflags(f, cpu_fprintf, fw->feat_names); - (*cpu_fprintf)(f, "\n"); + listflags(buf, sizeof(buf), (uint32_t)~0, fw->feat_names, 1); + (*cpu_fprintf)(f, " %s\n", buf); } } @@ -2134,35 +2149,27 @@ out: return cpu; } -CPUX86State *cpu_x86_init_user(const char *cpu_model) +X86CPU *cpu_x86_init(const char *cpu_model) { Error *error = NULL; X86CPU *cpu; cpu = cpu_x86_create(cpu_model, NULL, &error); if (error) { - goto error; - } - - object_property_set_int(OBJECT(cpu), CPU(cpu)->cpu_index, "apic-id", - &error); - if (error) { - goto error; + goto out; } object_property_set_bool(OBJECT(cpu), true, "realized", &error); - if (error) { - goto error; - } - return &cpu->env; - -error: - error_report_err(error); - if (cpu != NULL) { - object_unref(OBJECT(cpu)); +out: + if (error) { + error_report_err(error); + if (cpu != NULL) { + object_unref(OBJECT(cpu)); + cpu = NULL; + } } - return NULL; + return cpu; } static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data) @@ -2220,6 +2227,14 @@ void x86_cpudef_setup(void) } } +static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + *ebx = env->cpuid_vendor1; + *edx = env->cpuid_vendor2; + *ecx = env->cpuid_vendor3; +} + void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -2253,14 +2268,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, switch(index) { case 0: *eax = env->cpuid_level; - *ebx = env->cpuid_vendor1; - *edx = env->cpuid_vendor2; - *ecx = env->cpuid_vendor3; + get_cpuid_vendor(env, ebx, ecx, edx); break; case 1: *eax = env->cpuid_version; - *ebx = (cpu->apic_id << 24) | - 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ + *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ *ecx = env->features[FEAT_1_ECX]; *edx = env->features[FEAT_1_EDX]; if (cs->nr_cores * cs->nr_threads > 1) { @@ -2449,9 +2461,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * So dont set it here for Intel to make Linux guests happy. */ if (cs->nr_cores * cs->nr_threads > 1) { - if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 || - env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 || - env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) { + 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 */ } } @@ -2707,6 +2721,7 @@ static void mce_init(X86CPU *cpu) #ifndef CONFIG_USER_ONLY static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) { + CPUX86State *env = &cpu->env; DeviceState *dev = DEVICE(cpu); APICCommonState *apic; const char *apic_type = "apic"; @@ -2725,7 +2740,7 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) object_property_add_child(OBJECT(cpu), "apic", OBJECT(cpu->apic_state), NULL); - qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id); + qdev_prop_set_uint8(cpu->apic_state, "id", env->cpuid_apic_id); /* TODO: convert to link<> */ apic = APIC_COMMON(cpu->apic_state); apic->cpu = cpu; @@ -2765,11 +2780,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) Error *local_err = NULL; static bool ht_warned; - if (cpu->apic_id < 0) { - error_setg(errp, "apic-id property was not initialized properly"); - return; - } - if (env->features[FEAT_7_0_EBX] && env->cpuid_level < 7) { env->cpuid_level = 7; } @@ -2834,6 +2844,39 @@ out: } } +/* Enables contiguous-apic-ID mode, for compatibility */ +static bool compat_apic_id_mode; + +void enable_compat_apic_id_mode(void) +{ + compat_apic_id_mode = true; +} + +/* Calculates initial APIC ID for a specific CPU index + * + * Currently we need to be able to calculate the APIC ID from the CPU index + * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have + * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of + * all CPUs up to max_cpus. + */ +uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index) +{ + uint32_t correct_id; + static bool warned; + + correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index); + if (compat_apic_id_mode) { + if (cpu_index != correct_id && !warned) { + error_report("APIC IDs set in compatibility mode, " + "CPU topology won't match the configuration"); + warned = true; + } + return cpu_index; + } else { + return correct_id; + } +} + static void x86_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); @@ -2880,7 +2923,7 @@ static void x86_cpu_initfn(Object *obj) NULL, NULL, (void *)cpu->filtered_features, NULL); cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY; - cpu->apic_id = -1; + env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index); x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort); @@ -2894,8 +2937,9 @@ static void x86_cpu_initfn(Object *obj) static int64_t x86_cpu_get_arch_id(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; - return cpu->apic_id; + return env->cpuid_apic_id; } static bool x86_cpu_get_paging_enabled(const CPUState *cs) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index f0e6ca4843..478450cfb6 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -944,6 +944,7 @@ typedef struct CPUX86State { uint32_t cpuid_version; FeatureWordArray features; uint32_t cpuid_model[12]; + uint32_t cpuid_apic_id; /* MTRRs */ uint64_t mtrr_fixed[11]; @@ -981,6 +982,7 @@ typedef struct CPUX86State { #include "cpu-qom.h" +X86CPU *cpu_x86_init(const char *cpu_model); X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge, Error **errp); int cpu_x86_exec(CPUX86State *s); @@ -1169,9 +1171,14 @@ uint64_t cpu_get_tsc(CPUX86State *env); # define PHYS_ADDR_MASK 0xfffffffffLL # endif -/* CPU creation function for *-user */ -CPUX86State *cpu_x86_init_user(const char *cpu_model); -#define cpu_init cpu_x86_init_user +static inline CPUX86State *cpu_init(const char *cpu_model) +{ + X86CPU *cpu = cpu_x86_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} #define cpu_exec cpu_x86_exec #define cpu_gen_code cpu_x86_gen_code diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 27fe2be653..40d6a14c85 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -430,7 +430,7 @@ static void cpu_update_state(void *opaque, int running, RunState state) unsigned long kvm_arch_vcpu_id(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); - return cpu->apic_id; + return cpu->env.cpuid_apic_id; } #ifndef KVM_CPUID_SIGNATURE_NEXT diff --git a/include/hw/i386/topology.h b/target-i386/topology.h index 9c6f3a937a..07a6c5fb55 100644 --- a/include/hw/i386/topology.h +++ b/target-i386/topology.h @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef HW_I386_TOPOLOGY_H -#define HW_I386_TOPOLOGY_H +#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: @@ -131,4 +131,4 @@ static inline apic_id_t x86_apicid_from_cpu_idx(unsigned nr_cores, return apicid_from_topo_ids(nr_cores, nr_threads, pkg_id, core_id, smt_id); } -#endif /* HW_I386_TOPOLOGY_H */ +#endif /* TARGET_I386_TOPOLOGY_H */ diff --git a/tests/Makefile b/tests/Makefile index 7d4b96d4fd..307035c26c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -239,6 +239,8 @@ $(test-obj-y): QEMU_INCLUDES += -Itests QEMU_CFLAGS += -I$(SRC_PATH)/tests qom-core-obj = qom/object.o qom/qom-qobject.o qom/container.o +tests/test-x86-cpuid.o: QEMU_INCLUDES += -I$(SRC_PATH)/target-i386 + tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a diff --git a/tests/test-x86-cpuid.c b/tests/test-x86-cpuid.c index 6cd20d4a23..8d9f96a113 100644 --- a/tests/test-x86-cpuid.c +++ b/tests/test-x86-cpuid.c @@ -24,7 +24,7 @@ #include <glib.h> -#include "hw/i386/topology.h" +#include "topology.h" static void test_topo_bits(void) { |