diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-03-02 14:25:48 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-03-02 14:25:48 +0000 |
commit | b8a173b25c887a606681fc35a46702c164d5b2d0 (patch) | |
tree | 50860f62eacc4e60cc5f0a504d815218f8322676 /target-i386 | |
parent | 5de090464f1ec5360c4f30faa01d8a9f8826cd58 (diff) | |
parent | de13197a38cf45c990802661a057f64a05426cbc (diff) |
Merge remote-tracking branch 'remotes/ehabkost/tags/x86-pull-request' into staging
* remotes/ehabkost/tags/x86-pull-request:
target-i386: Move APIC ID compatibility code to pc.c
target-i386: Require APIC ID to be explicitly set before CPU realize
target-i386: Set APIC ID using cpu_index on CONFIG_USER
linux-user: Check for cpu_init() errors
target-i386: Move CPUX86State.cpuid_apic_id to X86CPU.apic_id
target-i386: Simplify error handling on cpu_x86_init_user()
target-i386: Eliminate cpu_init() function
target-i386: Rename cpu_x86_init() to cpu_x86_init_user()
target-i386: Move topology.h to include/hw/i386
target-i386: Eliminate unnecessary get_cpuid_vendor() function
target-i386: Simplify listflags() function
Conflicts:
target-i386/cpu.c
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-i386')
-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 | 134 |
5 files changed, 56 insertions, 240 deletions
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index b557b619cf..31a0c1e776 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -93,6 +93,7 @@ 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 d543e2b537..14c6c4abaf 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -25,7 +25,6 @@ #include "sysemu/kvm.h" #include "sysemu/cpus.h" #include "kvm_i386.h" -#include "topology.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -1690,7 +1689,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->env.cpuid_apic_id; + int64_t value = cpu->apic_id; visit_type_int(v, &value, name, errp); } @@ -1723,11 +1722,11 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque, return; } - if ((value != cpu->env.cpuid_apic_id) && cpu_exists(value)) { + if ((value != cpu->apic_id) && cpu_exists(value)) { error_setg(errp, "CPU with APIC ID %" PRIi64 " exists", value); return; } - cpu->env.cpuid_apic_id = value; + cpu->apic_id = value; } /* Generic getter for "feature-words" and "filtered-features" properties */ @@ -1911,34 +1910,19 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features, } } -/* 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. +/* Print all cpuid feature names 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; +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; } + } } /* generate CPU information. */ @@ -1963,8 +1947,9 @@ 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]; - listflags(buf, sizeof(buf), (uint32_t)~0, fw->feat_names, 1); - (*cpu_fprintf)(f, " %s\n", buf); + (*cpu_fprintf)(f, " "); + listflags(f, cpu_fprintf, fw->feat_names); + (*cpu_fprintf)(f, "\n"); } } @@ -2149,27 +2134,35 @@ out: return cpu; } -X86CPU *cpu_x86_init(const char *cpu_model) +CPUX86State *cpu_x86_init_user(const char *cpu_model) { Error *error = NULL; X86CPU *cpu; cpu = cpu_x86_create(cpu_model, NULL, &error); if (error) { - goto out; + goto error; } - object_property_set_bool(OBJECT(cpu), true, "realized", &error); + object_property_set_int(OBJECT(cpu), CPU(cpu)->cpu_index, "apic-id", + &error); + if (error) { + goto error; + } -out: + object_property_set_bool(OBJECT(cpu), true, "realized", &error); if (error) { - error_report_err(error); - if (cpu != NULL) { - object_unref(OBJECT(cpu)); - cpu = NULL; - } + goto error; } - return cpu; + + return &cpu->env; + +error: + error_report_err(error); + if (cpu != NULL) { + object_unref(OBJECT(cpu)); + } + return NULL; } static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data) @@ -2227,14 +2220,6 @@ 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) @@ -2268,11 +2253,14 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, switch(index) { case 0: *eax = env->cpuid_level; - get_cpuid_vendor(env, ebx, ecx, edx); + *ebx = env->cpuid_vendor1; + *edx = env->cpuid_vendor2; + *ecx = env->cpuid_vendor3; break; case 1: *eax = env->cpuid_version; - *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ + *ebx = (cpu->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) { @@ -2461,11 +2449,9 @@ 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) { - 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) { + if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 || + env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 || + env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) { *ecx |= 1 << 1; /* CmpLegacy bit */ } } @@ -2721,7 +2707,6 @@ 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"; @@ -2740,7 +2725,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", env->cpuid_apic_id); + qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id); /* TODO: convert to link<> */ apic = APIC_COMMON(cpu->apic_state); apic->cpu = cpu; @@ -2780,6 +2765,11 @@ 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; } @@ -2844,39 +2834,6 @@ 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); @@ -2923,7 +2880,7 @@ static void x86_cpu_initfn(Object *obj) NULL, NULL, (void *)cpu->filtered_features, NULL); cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY; - env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index); + cpu->apic_id = -1; x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort); @@ -2937,9 +2894,8 @@ 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 env->cpuid_apic_id; + return cpu->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 478450cfb6..f0e6ca4843 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -944,7 +944,6 @@ 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]; @@ -982,7 +981,6 @@ 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); @@ -1171,14 +1169,9 @@ uint64_t cpu_get_tsc(CPUX86State *env); # define PHYS_ADDR_MASK 0xfffffffffLL # endif -static inline CPUX86State *cpu_init(const char *cpu_model) -{ - X86CPU *cpu = cpu_x86_init(cpu_model); - if (cpu == NULL) { - return NULL; - } - return &cpu->env; -} +/* CPU creation function for *-user */ +CPUX86State *cpu_x86_init_user(const char *cpu_model); +#define cpu_init cpu_x86_init_user #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 40d6a14c85..27fe2be653 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->env.cpuid_apic_id; + return cpu->apic_id; } #ifndef KVM_CPUID_SIGNATURE_NEXT diff --git a/target-i386/topology.h b/target-i386/topology.h deleted file mode 100644 index 07a6c5fb55..0000000000 --- a/target-i386/topology.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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 <stdint.h> -#include <string.h> - -#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); - count -= 1; - return count ? 32 - clz32(count) : 0; -} - -/* 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 */ |