#include "qapi/visitor.h"
#include "sysemu/arch_init.h"
-#include "hyperv.h"
-
#include "hw/hw.h"
#if defined(CONFIG_KVM)
#include <linux/kvm_para.h>
#include "hw/i386/apic_internal.h"
#endif
+
+/* Cache topology CPUID constants: */
+
+/* CPUID Leaf 2 Descriptors */
+
+#define CPUID_2_L1D_32KB_8WAY_64B 0x2c
+#define CPUID_2_L1I_32KB_8WAY_64B 0x30
+#define CPUID_2_L2_2MB_8WAY_64B 0x7d
+
+
+/* CPUID Leaf 4 constants: */
+
+/* EAX: */
+#define CPUID_4_TYPE_DCACHE 1
+#define CPUID_4_TYPE_ICACHE 2
+#define CPUID_4_TYPE_UNIFIED 3
+
+#define CPUID_4_LEVEL(l) ((l) << 5)
+
+#define CPUID_4_SELF_INIT_LEVEL (1 << 8)
+#define CPUID_4_FULLY_ASSOC (1 << 9)
+
+/* EDX: */
+#define CPUID_4_NO_INVD_SHARING (1 << 0)
+#define CPUID_4_INCLUSIVE (1 << 1)
+#define CPUID_4_COMPLEX_IDX (1 << 2)
+
+#define ASSOC_FULL 0xFF
+
+/* AMD associativity encoding used on CPUID Leaf 0x80000006: */
+#define AMD_ENC_ASSOC(a) (a <= 1 ? a : \
+ a == 2 ? 0x2 : \
+ a == 4 ? 0x4 : \
+ a == 8 ? 0x6 : \
+ a == 16 ? 0x8 : \
+ a == 32 ? 0xA : \
+ a == 48 ? 0xB : \
+ a == 64 ? 0xC : \
+ a == 96 ? 0xD : \
+ a == 128 ? 0xE : \
+ a == ASSOC_FULL ? 0xF : \
+ 0 /* invalid value */)
+
+
+/* Definitions of the hardcoded cache entries we expose: */
+
+/* L1 data cache: */
+#define L1D_LINE_SIZE 64
+#define L1D_ASSOCIATIVITY 8
+#define L1D_SETS 64
+#define L1D_PARTITIONS 1
+/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
+#define L1D_DESCRIPTOR CPUID_2_L1D_32KB_8WAY_64B
+/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
+#define L1D_LINES_PER_TAG 1
+#define L1D_SIZE_KB_AMD 64
+#define L1D_ASSOCIATIVITY_AMD 2
+
+/* L1 instruction cache: */
+#define L1I_LINE_SIZE 64
+#define L1I_ASSOCIATIVITY 8
+#define L1I_SETS 64
+#define L1I_PARTITIONS 1
+/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
+#define L1I_DESCRIPTOR CPUID_2_L1I_32KB_8WAY_64B
+/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
+#define L1I_LINES_PER_TAG 1
+#define L1I_SIZE_KB_AMD 64
+#define L1I_ASSOCIATIVITY_AMD 2
+
+/* Level 2 unified cache: */
+#define L2_LINE_SIZE 64
+#define L2_ASSOCIATIVITY 16
+#define L2_SETS 4096
+#define L2_PARTITIONS 1
+/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 4MiB */
+/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */
+#define L2_DESCRIPTOR CPUID_2_L2_2MB_8WAY_64B
+/*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */
+#define L2_LINES_PER_TAG 1
+#define L2_SIZE_KB_AMD 512
+
+/* No L3 cache: */
+#define L3_SIZE_KB 0 /* disabled */
+#define L3_ASSOCIATIVITY 0 /* disabled */
+#define L3_LINES_PER_TAG 0 /* disabled */
+#define L3_LINE_SIZE 0 /* disabled */
+
+/* TLB definitions: */
+
+#define L1_DTLB_2M_ASSOC 1
+#define L1_DTLB_2M_ENTRIES 255
+#define L1_DTLB_4K_ASSOC 1
+#define L1_DTLB_4K_ENTRIES 255
+
+#define L1_ITLB_2M_ASSOC 1
+#define L1_ITLB_2M_ENTRIES 255
+#define L1_ITLB_4K_ASSOC 1
+#define L1_ITLB_4K_ENTRIES 255
+
+#define L2_DTLB_2M_ASSOC 0 /* disabled */
+#define L2_DTLB_2M_ENTRIES 0 /* disabled */
+#define L2_DTLB_4K_ASSOC 4
+#define L2_DTLB_4K_ENTRIES 512
+
+#define L2_ITLB_2M_ASSOC 0 /* disabled */
+#define L2_ITLB_2M_ENTRIES 0 /* disabled */
+#define L2_ITLB_4K_ASSOC 4
+#define L2_ITLB_4K_ENTRIES 512
+
+
+
static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
uint32_t vendor2, uint32_t vendor3)
{
error_propagate(errp, err);
}
-static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
+static int cpu_x86_find_by_name(X86CPU *cpu, x86_def_t *x86_cpu_def,
+ const char *name)
{
x86_def_t *def;
+ Error *err = NULL;
int i;
if (name == NULL) {
}
if (kvm_enabled() && strcmp(name, "host") == 0) {
kvm_cpu_fill_host(x86_cpu_def);
+ object_property_set_bool(OBJECT(cpu), true, "pmu", &err);
+ assert_no_error(err);
return 0;
}
object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp);
} else if (!strcmp(featurestr, "hv-spinlocks")) {
char *err;
+ const int min = 0xFFF;
numvalue = strtoul(val, &err, 0);
if (!*val || *err) {
error_setg(errp, "bad numerical value %s", val);
goto out;
}
- hyperv_set_spinlock_retries(numvalue);
+ if (numvalue < min) {
+ fprintf(stderr, "hv-spinlocks value shall always be >= 0x%x"
+ ", fixup will be removed in future versions\n",
+ min);
+ numvalue = min;
+ }
+ cpu->hyperv_spinlock_attempts = numvalue;
} else {
error_setg(errp, "unrecognized feature %s", featurestr);
goto out;
} else if (!strcmp(featurestr, "enforce")) {
check_cpuid = enforce_cpuid = 1;
} else if (!strcmp(featurestr, "hv_relaxed")) {
- hyperv_enable_relaxed_timing(true);
+ cpu->hyperv_relaxed_timing = true;
} else if (!strcmp(featurestr, "hv_vapic")) {
- hyperv_enable_vapic_recommended(true);
+ cpu->hyperv_vapic = true;
} else {
error_setg(errp, "feature string `%s' not in format (+feature|"
"-feature|feature=xyz)", featurestr);
memset(def, 0, sizeof(*def));
- if (cpu_x86_find_by_name(def, name) < 0) {
+ if (cpu_x86_find_by_name(cpu, def, name) < 0) {
error_setg(errp, "Unable to find CPU definition: %s", name);
return;
}
}
out:
- error_propagate(errp, error);
+ if (error != NULL) {
+ error_propagate(errp, error);
+ object_unref(OBJECT(cpu));
+ cpu = NULL;
+ }
g_strfreev(model_pieces);
return cpu;
}
out:
if (error) {
- fprintf(stderr, "%s\n", error_get_pretty(error));
+ error_report("%s", error_get_pretty(error));
error_free(error);
if (cpu != NULL) {
object_unref(OBJECT(cpu));
break;
case 2:
/* cache info: needed for Pentium Pro compatibility */
- *eax = 1;
+ *eax = 1; /* Number of CPUID[EAX=2] calls required */
*ebx = 0;
*ecx = 0;
- *edx = 0x2c307d;
+ *edx = (L1D_DESCRIPTOR << 16) | \
+ (L1I_DESCRIPTOR << 8) | \
+ (L2_DESCRIPTOR);
break;
case 4:
/* cache info: needed for Core compatibility */
}
switch (count) {
case 0: /* L1 dcache info */
- *eax |= 0x0000121;
- *ebx = 0x1c0003f;
- *ecx = 0x000003f;
- *edx = 0x0000001;
+ *eax |= CPUID_4_TYPE_DCACHE | \
+ CPUID_4_LEVEL(1) | \
+ CPUID_4_SELF_INIT_LEVEL;
+ *ebx = (L1D_LINE_SIZE - 1) | \
+ ((L1D_PARTITIONS - 1) << 12) | \
+ ((L1D_ASSOCIATIVITY - 1) << 22);
+ *ecx = L1D_SETS - 1;
+ *edx = CPUID_4_NO_INVD_SHARING;
break;
case 1: /* L1 icache info */
- *eax |= 0x0000122;
- *ebx = 0x1c0003f;
- *ecx = 0x000003f;
- *edx = 0x0000001;
+ *eax |= CPUID_4_TYPE_ICACHE | \
+ CPUID_4_LEVEL(1) | \
+ CPUID_4_SELF_INIT_LEVEL;
+ *ebx = (L1I_LINE_SIZE - 1) | \
+ ((L1I_PARTITIONS - 1) << 12) | \
+ ((L1I_ASSOCIATIVITY - 1) << 22);
+ *ecx = L1I_SETS - 1;
+ *edx = CPUID_4_NO_INVD_SHARING;
break;
case 2: /* L2 cache info */
- *eax |= 0x0000143;
+ *eax |= CPUID_4_TYPE_UNIFIED | \
+ CPUID_4_LEVEL(2) | \
+ CPUID_4_SELF_INIT_LEVEL;
if (cs->nr_threads > 1) {
*eax |= (cs->nr_threads - 1) << 14;
}
- *ebx = 0x3c0003f;
- *ecx = 0x0000fff;
- *edx = 0x0000001;
+ *ebx = (L2_LINE_SIZE - 1) | \
+ ((L2_PARTITIONS - 1) << 12) | \
+ ((L2_ASSOCIATIVITY - 1) << 22);
+ *ecx = L2_SETS - 1;
+ *edx = CPUID_4_NO_INVD_SHARING;
break;
default: /* end of info */
*eax = 0;
break;
case 0xA:
/* Architectural Performance Monitoring Leaf */
- if (kvm_enabled()) {
+ if (kvm_enabled() && cpu->enable_pmu) {
KVMState *s = cs->kvm_state;
*eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX);
break;
case 0x80000005:
/* cache info (L1 cache) */
- *eax = 0x01ff01ff;
- *ebx = 0x01ff01ff;
- *ecx = 0x40020140;
- *edx = 0x40020140;
+ *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \
+ (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES);
+ *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \
+ (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES);
+ *ecx = (L1D_SIZE_KB_AMD << 24) | (L1D_ASSOCIATIVITY_AMD << 16) | \
+ (L1D_LINES_PER_TAG << 8) | (L1D_LINE_SIZE);
+ *edx = (L1I_SIZE_KB_AMD << 24) | (L1I_ASSOCIATIVITY_AMD << 16) | \
+ (L1I_LINES_PER_TAG << 8) | (L1I_LINE_SIZE);
break;
case 0x80000006:
/* cache info (L2 cache) */
- *eax = 0;
- *ebx = 0x42004200;
- *ecx = 0x02008140;
- *edx = 0;
+ *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \
+ (L2_DTLB_2M_ENTRIES << 16) | \
+ (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \
+ (L2_ITLB_2M_ENTRIES);
+ *ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | \
+ (L2_DTLB_4K_ENTRIES << 16) | \
+ (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \
+ (L2_ITLB_4K_ENTRIES);
+ *ecx = (L2_SIZE_KB_AMD << 16) | \
+ (AMD_ENC_ASSOC(L2_ASSOCIATIVITY) << 12) | \
+ (L2_LINES_PER_TAG << 8) | (L2_LINE_SIZE);
+ *edx = ((L3_SIZE_KB/512) << 18) | \
+ (AMD_ENC_ASSOC(L3_ASSOCIATIVITY) << 12) | \
+ (L3_LINES_PER_TAG << 8) | (L3_LINE_SIZE);
break;
case 0x80000008:
/* virtual & phys address size in low 2 bytes. */
CPUX86State *env = &cpu->env;
int i;
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", s->cpu_index);
- log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP);
- }
-
xcc->parent_reset(s);
static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
{
+ CPUState *cs = CPU(dev);
X86CPU *cpu = X86_CPU(dev);
X86CPUClass *xcc = X86_CPU_GET_CLASS(dev);
CPUX86State *env = &cpu->env;
#endif
mce_init(cpu);
- qemu_init_vcpu(&cpu->env);
+ qemu_init_vcpu(cs);
x86_cpu_apic_realize(cpu, &local_err);
if (local_err != NULL) {
goto out;
}
- cpu_reset(CPU(cpu));
+ cpu_reset(cs);
xcc->parent_realize(dev, &local_err);
out:
x86_cpu_get_feature_words,
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);
/* init various static tables used in TCG mode */
return cpu->env.cr[0] & CR0_PG_MASK;
}
+static void x86_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ X86CPU *cpu = X86_CPU(cs);
+
+ cpu->env.eip = value;
+}
+
+static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+ X86CPU *cpu = X86_CPU(cs);
+
+ cpu->env.eip = tb->pc - tb->cs_base;
+}
+
+static Property x86_cpu_properties[] = {
+ DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
+ DEFINE_PROP_END_OF_LIST()
+};
+
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
{
X86CPUClass *xcc = X86_CPU_CLASS(oc);
xcc->parent_realize = dc->realize;
dc->realize = x86_cpu_realizefn;
dc->bus_type = TYPE_ICC_BUS;
+ dc->props = x86_cpu_properties;
xcc->parent_reset = cc->reset;
cc->reset = x86_cpu_reset;
+ cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP;
cc->do_interrupt = x86_cpu_do_interrupt;
+ cc->dump_state = x86_cpu_dump_state;
+ cc->set_pc = x86_cpu_set_pc;
+ cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
+ cc->gdb_read_register = x86_cpu_gdb_read_register;
+ cc->gdb_write_register = x86_cpu_gdb_write_register;
cc->get_arch_id = x86_cpu_get_arch_id;
cc->get_paging_enabled = x86_cpu_get_paging_enabled;
#ifndef CONFIG_USER_ONLY
cc->get_memory_mapping = x86_cpu_get_memory_mapping;
+ cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
cc->write_elf64_note = x86_cpu_write_elf64_note;
cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote;
cc->write_elf32_note = x86_cpu_write_elf32_note;
cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
+ cc->vmsd = &vmstate_x86_cpu;
#endif
- cpu_class_set_vmsd(cc, &vmstate_x86_cpu);
+ cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25;
}
static const TypeInfo x86_cpu_type_info = {