aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-03-02 14:25:48 +0000
committerPeter Maydell <peter.maydell@linaro.org>2015-03-02 14:25:48 +0000
commitb8a173b25c887a606681fc35a46702c164d5b2d0 (patch)
tree50860f62eacc4e60cc5f0a504d815218f8322676 /target-i386
parent5de090464f1ec5360c4f30faa01d8a9f8826cd58 (diff)
parentde13197a38cf45c990802661a057f64a05426cbc (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.h1
-rw-r--r--target-i386/cpu.c146
-rw-r--r--target-i386/cpu.h13
-rw-r--r--target-i386/kvm.c2
-rw-r--r--target-i386/topology.h134
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 */