#include "sysemu/reset.h"
#include "sysemu/hvf.h"
#include "sysemu/cpus.h"
+#include "sysemu/xen.h"
#include "kvm_i386.h"
#include "sev_i386.h"
#include "hw/i386/topology.h"
#ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h"
-#include "hw/xen/xen.h"
#include "hw/i386/apic_internal.h"
#include "hw/boards.h"
#endif
}
}
-/*
- * Definitions used for building CPUID Leaf 0x8000001D and 0x8000001E
- * Please refer to the AMD64 Architecture Programmer’s Manual Volume 3.
- * Define the constants to build the cpu topology. Right now, TOPOEXT
- * feature is enabled only on EPYC. So, these constants are based on
- * EPYC supported configurations. We may need to handle the cases if
- * these values change in future.
- */
-/* Maximum core complexes in a node */
-#define MAX_CCX 2
-/* Maximum cores in a core complex */
-#define MAX_CORES_IN_CCX 4
-/* Maximum cores in a node */
-#define MAX_CORES_IN_NODE 8
-/* Maximum nodes in a socket */
-#define MAX_NODES_PER_SOCKET 4
-
-/*
- * Figure out the number of nodes required to build this config.
- * Max cores in a node is 8
- */
-static int nodes_in_socket(int nr_cores)
-{
- int nodes;
-
- nodes = DIV_ROUND_UP(nr_cores, MAX_CORES_IN_NODE);
-
- /* Hardware does not support config with 3 nodes, return 4 in that case */
- return (nodes == 3) ? 4 : nodes;
-}
-
-/*
- * Decide the number of cores in a core complex with the given nr_cores using
- * following set constants MAX_CCX, MAX_CORES_IN_CCX, MAX_CORES_IN_NODE and
- * MAX_NODES_PER_SOCKET. Maintain symmetry as much as possible
- * L3 cache is shared across all cores in a core complex. So, this will also
- * tell us how many cores are sharing the L3 cache.
- */
-static int cores_in_core_complex(int nr_cores)
-{
- int nodes;
-
- /* Check if we can fit all the cores in one core complex */
- if (nr_cores <= MAX_CORES_IN_CCX) {
- return nr_cores;
- }
- /* Get the number of nodes required to build this config */
- nodes = nodes_in_socket(nr_cores);
-
- /*
- * Divide the cores accros all the core complexes
- * Return rounded up value
- */
- return DIV_ROUND_UP(nr_cores, nodes * MAX_CCX);
-}
-
/* Encode cache info for CPUID[8000001D] */
-static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs,
- uint32_t *eax, uint32_t *ebx,
- uint32_t *ecx, uint32_t *edx)
+static void encode_cache_cpuid8000001d(CPUCacheInfo *cache,
+ X86CPUTopoInfo *topo_info,
+ uint32_t *eax, uint32_t *ebx,
+ uint32_t *ecx, uint32_t *edx)
{
uint32_t l3_cores;
+ unsigned nodes = MAX(topo_info->nodes_per_pkg, 1);
+
assert(cache->size == cache->line_size * cache->associativity *
cache->partitions * cache->sets);
/* L3 is shared among multiple cores */
if (cache->level == 3) {
- l3_cores = cores_in_core_complex(cs->nr_cores);
- *eax |= ((l3_cores * cs->nr_threads) - 1) << 14;
+ l3_cores = DIV_ROUND_UP((topo_info->dies_per_pkg *
+ topo_info->cores_per_die *
+ topo_info->threads_per_core),
+ nodes);
+ *eax |= (l3_cores - 1) << 14;
} else {
- *eax |= ((cs->nr_threads - 1) << 14);
+ *eax |= ((topo_info->threads_per_core - 1) << 14);
}
assert(cache->line_size > 0);
(cache->complex_indexing ? CACHE_COMPLEX_IDX : 0);
}
-/* Data structure to hold the configuration info for a given core index */
-struct core_topology {
- /* core complex id of the current core index */
- int ccx_id;
- /*
- * Adjusted core index for this core in the topology
- * This can be 0,1,2,3 with max 4 cores in a core complex
- */
- int core_id;
- /* Node id for this core index */
- int node_id;
- /* Number of nodes in this config */
- int num_nodes;
-};
-
-/*
- * Build the configuration closely match the EPYC hardware. Using the EPYC
- * hardware configuration values (MAX_CCX, MAX_CORES_IN_CCX, MAX_CORES_IN_NODE)
- * right now. This could change in future.
- * nr_cores : Total number of cores in the config
- * core_id : Core index of the current CPU
- * topo : Data structure to hold all the config info for this core index
- */
-static void build_core_topology(int nr_cores, int core_id,
- struct core_topology *topo)
-{
- int nodes, cores_in_ccx;
-
- /* First get the number of nodes required */
- nodes = nodes_in_socket(nr_cores);
-
- cores_in_ccx = cores_in_core_complex(nr_cores);
-
- topo->node_id = core_id / (cores_in_ccx * MAX_CCX);
- topo->ccx_id = (core_id % (cores_in_ccx * MAX_CCX)) / cores_in_ccx;
- topo->core_id = core_id % cores_in_ccx;
- topo->num_nodes = nodes;
-}
-
/* Encode cache info for CPUID[8000001E] */
-static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu,
+static void encode_topo_cpuid8000001e(X86CPUTopoInfo *topo_info, X86CPU *cpu,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
- struct core_topology topo = {0};
- unsigned long nodes;
+ X86CPUTopoIDs topo_ids = {0};
+ unsigned long nodes = MAX(topo_info->nodes_per_pkg, 1);
int shift;
- build_core_topology(cs->nr_cores, cpu->core_id, &topo);
+ x86_topo_ids_from_apicid_epyc(cpu->apic_id, topo_info, &topo_ids);
+
*eax = cpu->apic_id;
/*
* CPUID_Fn8000001E_EBX
* 3 Core complex id
* 1:0 Core id
*/
- if (cs->nr_threads - 1) {
- *ebx = ((cs->nr_threads - 1) << 8) | (topo.node_id << 3) |
- (topo.ccx_id << 2) | topo.core_id;
- } else {
- *ebx = (topo.node_id << 4) | (topo.ccx_id << 3) | topo.core_id;
- }
+ *ebx = ((topo_info->threads_per_core - 1) << 8) | (topo_ids.node_id << 3) |
+ (topo_ids.core_id);
/*
* CPUID_Fn8000001E_ECX
* 31:11 Reserved
* 2 Socket id
* 1:0 Node id
*/
- if (topo.num_nodes <= 4) {
- *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) |
- topo.node_id;
+ if (nodes <= 4) {
+ *ecx = ((nodes - 1) << 8) | (topo_ids.pkg_id << 2) | topo_ids.node_id;
} else {
/*
* Node id fix up. Actual hardware supports up to 4 nodes. But with
* number of nodes. find_last_bit returns last set bit(0 based). Left
* shift(+1) the socket id to represent all the nodes.
*/
- nodes = topo.num_nodes - 1;
+ nodes -= 1;
shift = find_last_bit(&nodes, 8);
- *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << (shift + 1)) |
- topo.node_id;
+ *ecx = (nodes << 8) | (topo_ids.pkg_id << (shift + 1)) |
+ topo_ids.node_id;
}
*edx = 0;
}
.feat_names = {
NULL, NULL, "avx512-4vnniw", "avx512-4fmaps",
NULL, NULL, NULL, NULL,
- NULL, NULL, "md-clear", NULL,
+ "avx512-vp2intersect", NULL, "md-clear", NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL /* pconfig */, NULL,
NULL, NULL, NULL, NULL,
"clzero", NULL, "xsaveerptr", NULL,
NULL, NULL, NULL, NULL,
NULL, "wbnoinvd", NULL, NULL,
- "ibpb", NULL, NULL, NULL,
+ "ibpb", NULL, NULL, "amd-stibp",
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
"amd-ssbd", "virt-ssbd", "amd-no-ssb", NULL,
.index = MSR_IA32_CORE_CAPABILITY,
},
},
+ [FEAT_PERF_CAPABILITIES] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, "full-width-write", NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .msr = {
+ .index = MSR_IA32_PERF_CAPABILITIES,
+ },
+ },
[FEAT_VMX_PROCBASED_CTLS] = {
.type = MSR_FEATURE_WORD,
.from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY },
.to = { FEAT_CORE_CAPABILITY, ~0ull },
},
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_PDCM },
+ .to = { FEAT_PERF_CAPABILITIES, ~0ull },
+ },
{
.from = { FEAT_1_ECX, CPUID_EXT_VMX },
.to = { FEAT_VMX_PROCBASED_CTLS, ~0ull },
.from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VMFUNC },
.to = { FEAT_VMX_VMFUNC, ~0ull },
},
+ {
+ .from = { FEAT_8000_0001_ECX, CPUID_EXT3_SVM },
+ .to = { FEAT_SVM, ~0ull },
+ },
};
typedef struct X86RegisterInfo32 {
typedef struct X86CPUVersionDefinition {
X86CPUVersion version;
const char *alias;
+ const char *note;
PropValue *props;
} X86CPUVersionDefinition;
FeatureWordArray features;
const char *model_id;
CPUCaches *cache_info;
+
+ /* Use AMD EPYC encoding for apic id */
+ bool use_epyc_apic_id_encoding;
+
/*
* Definitions for alternative versions of CPU model.
* List is terminated by item with version == 0.
X86CPUDefinition *cpudef;
/* CPU model version */
X86CPUVersion version;
+ const char *note;
/*
* If true, this is an alias CPU model.
* This matters only for "-cpu help" and query-cpu-definitions
return def->versions ?: default_version_list;
}
+bool cpu_x86_use_epyc_apic_id_encoding(const char *cpu_type)
+{
+ X86CPUClass *xcc = X86_CPU_CLASS(object_class_by_name(cpu_type));
+
+ assert(xcc);
+ if (xcc->model && xcc->model->cpudef) {
+ return xcc->model->cpudef->use_epyc_apic_id_encoding;
+ } else {
+ return false;
+ }
+}
+
static CPUCaches epyc_cache_info = {
.l1d_cache = &(CPUCacheInfo) {
.type = DATA_CACHE,
},
};
+static CPUCaches epyc_rome_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ .type = DATA_CACHE,
+ .level = 1,
+ .size = 32 * KiB,
+ .line_size = 64,
+ .associativity = 8,
+ .partitions = 1,
+ .sets = 64,
+ .lines_per_tag = 1,
+ .self_init = 1,
+ .no_invd_sharing = true,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .size = 32 * KiB,
+ .line_size = 64,
+ .associativity = 8,
+ .partitions = 1,
+ .sets = 64,
+ .lines_per_tag = 1,
+ .self_init = 1,
+ .no_invd_sharing = true,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .size = 512 * KiB,
+ .line_size = 64,
+ .associativity = 8,
+ .partitions = 1,
+ .sets = 1024,
+ .lines_per_tag = 1,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .size = 16 * MiB,
+ .line_size = 64,
+ .associativity = 16,
+ .partitions = 1,
+ .sets = 16384,
+ .lines_per_tag = 1,
+ .self_init = true,
+ .inclusive = true,
+ .complex_indexing = true,
+ },
+};
+
/* The following VMX features are not supported by KVM and are left out in the
* CPU definitions:
*
.versions = (X86CPUVersionDefinition[]) {
{ .version = 1 },
{ .version = 2,
+ .note = "ARCH_CAPABILITIES",
.props = (PropValue[]) {
{ "arch-capabilities", "on" },
{ "rdctl-no", "on" },
},
{ .version = 3,
.alias = "Cascadelake-Server-noTSX",
+ .note = "ARCH_CAPABILITIES, no TSX",
.props = (PropValue[]) {
{ "hle", "off" },
{ "rtm", "off" },
{ .version = 1 },
{
.version = 2,
+ .note = "no TSX",
.alias = "Icelake-Client-noTSX",
.props = (PropValue[]) {
{ "hle", "off" },
{ .version = 1 },
{
.version = 2,
+ .note = "no TSX",
.alias = "Icelake-Server-noTSX",
.props = (PropValue[]) {
{ "hle", "off" },
{ /* end of list */ }
},
},
+ {
+ .version = 3,
+ .props = (PropValue[]) {
+ { "arch-capabilities", "on" },
+ { "rdctl-no", "on" },
+ { "ibrs-all", "on" },
+ { "skip-l1dfl-vmentry", "on" },
+ { "mds-no", "on" },
+ { "pschange-mc-no", "on" },
+ { "taa-no", "on" },
+ { /* end of list */ }
+ },
+ },
{ /* end of list */ }
}
},
.features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING,
.xlevel = 0x80000008,
.model_id = "Intel Atom Processor (Denverton)",
+ .versions = (X86CPUVersionDefinition[]) {
+ { .version = 1 },
+ {
+ .version = 2,
+ .note = "no MPX, no MONITOR",
+ .props = (PropValue[]) {
+ { "monitor", "off" },
+ { "mpx", "off" },
+ { /* end of list */ },
+ },
+ },
+ { /* end of list */ },
+ },
},
{
.name = "Snowridge",
CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED |
CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT |
CPUID_7_0_EBX_SHA_NI,
- /* Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component.
- */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
.xlevel = 0x8000001E,
.model_id = "AMD EPYC Processor",
.cache_info = &epyc_cache_info,
+ .use_epyc_apic_id_encoding = 1,
.versions = (X86CPUVersionDefinition[]) {
{ .version = 1 },
{
{ /* end of list */ }
}
},
+ {
+ .version = 3,
+ .props = (PropValue[]) {
+ { "ibpb", "on" },
+ { "perfctr-core", "on" },
+ { "clzero", "on" },
+ { "xsaveerptr", "on" },
+ { "xsaves", "on" },
+ { "model-id",
+ "AMD EPYC Processor" },
+ { /* end of list */ }
+ }
+ },
{ /* end of list */ }
}
},
.model_id = "Hygon Dhyana Processor",
.cache_info = &epyc_cache_info,
},
+ {
+ .name = "EPYC-Rome",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_AMD,
+ .family = 23,
+ .model = 49,
+ .stepping = 0,
+ .features[FEAT_1_EDX] =
+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH |
+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE |
+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE |
+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE |
+ CPUID_VME | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX |
+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT |
+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 |
+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB |
+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH |
+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM |
+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM |
+ CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE,
+ .features[FEAT_8000_0008_EBX] =
+ CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR |
+ CPUID_8000_0008_EBX_WBNOINVD | CPUID_8000_0008_EBX_IBPB |
+ CPUID_8000_0008_EBX_STIBP,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED |
+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT |
+ CPUID_7_0_EBX_SHA_NI | CPUID_7_0_EBX_CLWB,
+ .features[FEAT_7_0_ECX] =
+ CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_RDPID,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .features[FEAT_SVM] =
+ CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE,
+ .xlevel = 0x8000001E,
+ .model_id = "AMD EPYC-Rome Processor",
+ .cache_info = &epyc_rome_cache_info,
+ .use_epyc_apic_id_encoding = 1,
+ },
};
/* KVM-specific features that are automatically added/removed
host_vendor_fms(vendor, &family, &model, &stepping);
cpu_x86_fill_model_id(model_id);
- object_property_set_str(OBJECT(cpu), vendor, "vendor", &error_abort);
- object_property_set_int(OBJECT(cpu), family, "family", &error_abort);
- object_property_set_int(OBJECT(cpu), model, "model", &error_abort);
- object_property_set_int(OBJECT(cpu), stepping, "stepping",
+ object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort);
+ object_property_set_int(OBJECT(cpu), "family", family, &error_abort);
+ object_property_set_int(OBJECT(cpu), "model", model, &error_abort);
+ object_property_set_int(OBJECT(cpu), "stepping", stepping,
&error_abort);
- object_property_set_str(OBJECT(cpu), model_id, "model-id",
+ object_property_set_str(OBJECT(cpu), "model-id", model_id,
&error_abort);
if (kvm_enabled()) {
}
if (lmce_supported()) {
- object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort);
+ object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort);
}
} else {
- object_property_set_str(OBJECT(cpu), CPUID_VENDOR_AMD,
- "vendor", &error_abort);
- object_property_set_int(OBJECT(cpu), 6, "family", &error_abort);
- object_property_set_int(OBJECT(cpu), 6, "model", &error_abort);
- object_property_set_int(OBJECT(cpu), 3, "stepping", &error_abort);
- object_property_set_str(OBJECT(cpu),
+ object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD,
+ &error_abort);
+ object_property_set_int(OBJECT(cpu), "family", 6, &error_abort);
+ object_property_set_int(OBJECT(cpu), "model", 6, &error_abort);
+ object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort);
+ object_property_set_str(OBJECT(cpu), "model-id",
"QEMU TCG CPU version " QEMU_HW_VERSION,
- "model-id", &error_abort);
+ &error_abort);
}
- object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
+ object_property_set_bool(OBJECT(cpu), "pmu", true, &error_abort);
}
static const TypeInfo max_x86_cpu_type_info = {
CPUX86State *env = &cpu->env;
const int64_t min = 0;
const int64_t max = 0xff + 0xf;
- Error *local_err = NULL;
int64_t value;
- visit_type_int(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!visit_type_int(v, name, &value, errp)) {
return;
}
if (value < min || value > max) {
CPUX86State *env = &cpu->env;
const int64_t min = 0;
const int64_t max = 0xff;
- Error *local_err = NULL;
int64_t value;
- visit_type_int(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!visit_type_int(v, name, &value, errp)) {
return;
}
if (value < min || value > max) {
CPUX86State *env = &cpu->env;
const int64_t min = 0;
const int64_t max = 0xf;
- Error *local_err = NULL;
int64_t value;
- visit_type_int(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!visit_type_int(v, name, &value, errp)) {
return;
}
if (value < min || value > max) {
X86CPU *cpu = X86_CPU(obj);
const int64_t min = 0;
const int64_t max = INT64_MAX;
- Error *local_err = NULL;
int64_t value;
- visit_type_int(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!visit_type_int(v, name, &value, errp)) {
return;
}
if (value < min || value > max) {
g_autofree char *name = x86_cpu_class_get_model_name(cc);
g_autofree char *desc = g_strdup(cc->model_description);
g_autofree char *alias_of = x86_cpu_class_get_alias_of(cc);
+ g_autofree char *model_id = x86_cpu_class_get_model_id(cc);
if (!desc && alias_of) {
if (cc->model && cc->model->version == CPU_VERSION_AUTO) {
desc = g_strdup_printf("(alias of %s)", alias_of);
}
}
+ if (!desc && cc->model && cc->model->note) {
+ desc = g_strdup_printf("%s [%s]", model_id, cc->model->note);
+ }
if (!desc) {
- desc = x86_cpu_class_get_model_id(cc);
+ desc = g_strdup_printf("%s", model_id);
}
- qemu_printf("x86 %-20s %-48s\n", name, desc);
+ qemu_printf("x86 %-20s %-58s\n", name, desc);
}
/* list available CPU models and flags */
if (!pv->value) {
continue;
}
- object_property_parse(OBJECT(cpu), pv->value, pv->prop,
+ object_property_parse(OBJECT(cpu), pv->prop, pv->value,
&error_abort);
}
}
PropValue *p;
for (p = vdef->props; p && p->prop; p++) {
- object_property_parse(OBJECT(cpu), p->value, p->prop,
+ object_property_parse(OBJECT(cpu), p->prop, p->value,
&error_abort);
}
/* Load data from X86CPUDefinition into a X86CPU object
*/
-static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp)
+static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
{
X86CPUDefinition *def = model->cpudef;
CPUX86State *env = &cpu->env;
*/
/* CPU models only set _minimum_ values for level/xlevel: */
- object_property_set_uint(OBJECT(cpu), def->level, "min-level", errp);
- object_property_set_uint(OBJECT(cpu), def->xlevel, "min-xlevel", errp);
-
- object_property_set_int(OBJECT(cpu), def->family, "family", errp);
- object_property_set_int(OBJECT(cpu), def->model, "model", errp);
- object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp);
- object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
+ object_property_set_uint(OBJECT(cpu), "min-level", def->level,
+ &error_abort);
+ object_property_set_uint(OBJECT(cpu), "min-xlevel", def->xlevel,
+ &error_abort);
+
+ object_property_set_int(OBJECT(cpu), "family", def->family, &error_abort);
+ object_property_set_int(OBJECT(cpu), "model", def->model, &error_abort);
+ object_property_set_int(OBJECT(cpu), "stepping", def->stepping,
+ &error_abort);
+ object_property_set_str(OBJECT(cpu), "model-id", def->model_id,
+ &error_abort);
for (w = 0; w < FEATURE_WORDS; w++) {
env->features[w] = def->features[w];
}
vendor = host_vendor;
}
- object_property_set_str(OBJECT(cpu), vendor, "vendor", errp);
+ object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort);
x86_cpu_apply_version_props(cpu, model);
}
Error *err = NULL;
for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) {
- object_property_set_qobject(obj, qdict_entry_value(prop),
- qdict_entry_key(prop), &err);
- if (err) {
+ if (!object_property_set_qobject(obj, qdict_entry_key(prop),
+ qdict_entry_value(prop), &err)) {
break;
}
}
x86_cpu_versioned_model_name(def, vdef->version);
m->cpudef = def;
m->version = vdef->version;
+ m->note = vdef->note;
x86_register_cpu_model_type(name, m);
if (vdef->alias) {
uint32_t die_offset;
uint32_t limit;
uint32_t signature[3];
+ X86CPUTopoInfo topo_info;
+
+ topo_info.nodes_per_pkg = env->nr_nodes;
+ topo_info.dies_per_pkg = env->nr_dies;
+ topo_info.cores_per_die = cs->nr_cores;
+ topo_info.threads_per_core = cs->nr_threads;
/* Calculate & apply limits for different index ranges */
if (index >= 0xC0000000) {
*ebx |= (cs->nr_cores * cs->nr_threads) << 16;
*edx |= CPUID_HT;
}
+ if (!cpu->enable_pmu) {
+ *ecx &= ~CPUID_EXT_PDCM;
+ }
break;
case 2:
/* cache info: needed for Pentium Pro compatibility */
eax, ebx, ecx, edx);
break;
case 3: /* L3 cache info */
- die_offset = apicid_die_offset(env->nr_dies,
- cs->nr_cores, cs->nr_threads);
+ die_offset = apicid_die_offset(&topo_info);
if (cpu->enable_l3_cache) {
encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache,
(1 << die_offset), cs->nr_cores,
switch (count) {
case 0:
- *eax = apicid_core_offset(env->nr_dies,
- cs->nr_cores, cs->nr_threads);
+ *eax = apicid_core_offset(&topo_info);
*ebx = cs->nr_threads;
*ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
break;
case 1:
- *eax = apicid_pkg_offset(env->nr_dies,
- cs->nr_cores, cs->nr_threads);
+ *eax = env->pkg_offset;
*ebx = cs->nr_cores * cs->nr_threads;
*ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
break;
*edx = cpu->apic_id;
switch (count) {
case 0:
- *eax = apicid_core_offset(env->nr_dies, cs->nr_cores,
- cs->nr_threads);
+ *eax = apicid_core_offset(&topo_info);
*ebx = cs->nr_threads;
*ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
break;
case 1:
- *eax = apicid_die_offset(env->nr_dies, cs->nr_cores,
- cs->nr_threads);
+ *eax = apicid_die_offset(&topo_info);
*ebx = cs->nr_cores * cs->nr_threads;
*ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
break;
case 2:
- *eax = apicid_pkg_offset(env->nr_dies, cs->nr_cores,
- cs->nr_threads);
+ *eax = env->pkg_offset;
*ebx = env->nr_dies * cs->nr_cores * cs->nr_threads;
*ecx |= CPUID_TOPOLOGY_LEVEL_DIE;
break;
host_cpuid(index, 0, eax, ebx, ecx, edx);
break;
}
- *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \
+ *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) | \
+ *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) |
(L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES);
*ecx = encode_cache_cpuid80000005(env->cache_info_amd.l1d_cache);
*edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache);
host_cpuid(index, 0, eax, ebx, ecx, edx);
break;
}
- *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \
- (L2_DTLB_2M_ENTRIES << 16) | \
- (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \
+ *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) | \
+ *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);
encode_cache_cpuid80000006(env->cache_info_amd.l2_cache,
cpu->enable_l3_cache ?
*eax = cpu->phys_bits;
}
*ebx = env->features[FEAT_8000_0008_EBX];
- *ecx = 0;
- *edx = 0;
if (cs->nr_cores * cs->nr_threads > 1) {
- *ecx |= (cs->nr_cores * cs->nr_threads) - 1;
+ /*
+ * Bits 15:12 is "The number of bits in the initial
+ * Core::X86::Apic::ApicId[ApicId] value that indicate
+ * thread ID within a package". This is already stored at
+ * CPUX86State::pkg_offset.
+ * Bits 7:0 is "The number of threads in the package is NC+1"
+ */
+ *ecx = (env->pkg_offset << 12) |
+ ((cs->nr_cores * cs->nr_threads) - 1);
+ } else {
+ *ecx = 0;
}
+ *edx = 0;
break;
case 0x8000000A:
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
}
switch (count) {
case 0: /* L1 dcache info */
- encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache, cs,
- eax, ebx, ecx, edx);
+ encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache,
+ &topo_info, eax, ebx, ecx, edx);
break;
case 1: /* L1 icache info */
- encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache, cs,
- eax, ebx, ecx, edx);
+ encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache,
+ &topo_info, eax, ebx, ecx, edx);
break;
case 2: /* L2 cache info */
- encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache, cs,
- eax, ebx, ecx, edx);
+ encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache,
+ &topo_info, eax, ebx, ecx, edx);
break;
case 3: /* L3 cache info */
- encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache, cs,
- eax, ebx, ecx, edx);
+ encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache,
+ &topo_info, eax, ebx, ecx, edx);
break;
default: /* end of info */
*eax = *ebx = *ecx = *edx = 0;
break;
case 0x8000001E:
assert(cpu->core_id <= 255);
- encode_topo_cpuid8000001e(cs, cpu,
- eax, ebx, ecx, edx);
+ encode_topo_cpuid8000001e(&topo_info, cpu, eax, ebx, ecx, edx);
break;
case 0xC0000000:
*eax = env->cpuid_xlevel2;
}
}
-/* CPUClass::reset() */
-static void x86_cpu_reset(CPUState *s)
+static void x86_cpu_reset(DeviceState *dev)
{
+ CPUState *s = CPU(dev);
X86CPU *cpu = X86_CPU(s);
X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
CPUX86State *env = &cpu->env;
uint64_t xcr0;
int i;
- xcc->parent_reset(s);
+ xcc->parent_reset(dev);
memset(env, 0, offsetof(CPUX86State, end_reset_fields));
cpu->apic_state = DEVICE(object_new_with_class(apic_class));
object_property_add_child(OBJECT(cpu), "lapic",
- OBJECT(cpu->apic_state), &error_abort);
+ OBJECT(cpu->apic_state));
object_unref(OBJECT(cpu->apic_state));
qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
if (cpu->apic_state == NULL) {
return;
}
- object_property_set_bool(OBJECT(cpu->apic_state), true, "realized",
- errp);
+ qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
/* Map APIC MMIO area */
apic = APIC_COMMON(cpu->apic_state);
if (smram) {
cpu->smram = g_new(MemoryRegion, 1);
memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram",
- smram, 0, 1ull << 32);
+ smram, 0, 4 * GiB);
memory_region_set_enabled(cpu->smram, true);
memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1);
}
for (l = plus_features; l; l = l->next) {
const char *prop = l->data;
- object_property_set_bool(OBJECT(cpu), true, prop, &local_err);
- if (local_err) {
+ if (!object_property_set_bool(OBJECT(cpu), prop, true, &local_err)) {
goto out;
}
}
for (l = minus_features; l; l = l->next) {
const char *prop = l->data;
- object_property_set_bool(OBJECT(cpu), false, prop, &local_err);
- if (local_err) {
+ if (!object_property_set_bool(OBJECT(cpu), prop, false, &local_err)) {
goto out;
}
}
*/
env->features[w] |=
x86_cpu_get_supported_feature_word(w, cpu->migratable) &
- ~env->user_features[w] & \
+ ~env->user_features[w] &
~feature_word_info[w].no_autoenable_flags;
}
}
x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE);
/* Intel Processor Trace requires CPUID[0x14] */
- if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) &&
- kvm_enabled() && cpu->intel_pt_auto_level) {
- x86_cpu_adjust_level(cpu, &cpu->env.cpuid_min_level, 0x14);
+ if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT)) {
+ if (cpu->intel_pt_auto_level) {
+ x86_cpu_adjust_level(cpu, &cpu->env.cpuid_min_level, 0x14);
+ } else if (cpu->env.cpuid_min_level < 0x14) {
+ mark_unavailable_features(cpu, FEAT_7_0_EBX,
+ CPUID_7_0_EBX_INTEL_PT,
+ "Intel PT need CPUID leaf 0x14, please set by \"-cpu ...,+intel-pt,level=0x14\"");
+ }
}
/* CPU topology with multi-dies support requires CPUID[0x1F] */
}
}
-static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp)
+static void x86_cpu_unrealizefn(DeviceState *dev)
{
X86CPU *cpu = X86_CPU(dev);
X86CPUClass *xcc = X86_CPU_GET_CLASS(dev);
- Error *local_err = NULL;
#ifndef CONFIG_USER_ONLY
cpu_remove_sync(CPU(dev));
cpu->apic_state = NULL;
}
- xcc->parent_unrealize(dev, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
+ xcc->parent_unrealize(dev);
}
typedef struct BitProperty {
DeviceState *dev = DEVICE(obj);
X86CPU *cpu = X86_CPU(obj);
BitProperty *fp = opaque;
- Error *local_err = NULL;
bool value;
if (dev->realized) {
return;
}
- visit_type_bool(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!visit_type_bool(v, name, &value, errp)) {
return;
}
object_property_add(OBJECT(cpu), prop_name, "bool",
x86_cpu_get_bit_prop,
x86_cpu_set_bit_prop,
- x86_cpu_release_bit_prop, fp, &error_abort);
+ x86_cpu_release_bit_prop, fp);
}
}
x86_cpu_register_bit_prop(cpu, name, w, bitnr);
}
+#if !defined(CONFIG_USER_ONLY)
static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
errp);
qapi_free_GuestPanicInformation(panic_info);
}
+#endif /* !CONFIG_USER_ONLY */
static void x86_cpu_initfn(Object *obj)
{
FeatureWord w;
env->nr_dies = 1;
+ env->nr_nodes = 1;
cpu_set_cpustate_pointers(cpu);
object_property_add(obj, "family", "int",
x86_cpuid_version_get_family,
- x86_cpuid_version_set_family, NULL, NULL, NULL);
+ x86_cpuid_version_set_family, NULL, NULL);
object_property_add(obj, "model", "int",
x86_cpuid_version_get_model,
- x86_cpuid_version_set_model, NULL, NULL, NULL);
+ x86_cpuid_version_set_model, NULL, NULL);
object_property_add(obj, "stepping", "int",
x86_cpuid_version_get_stepping,
- x86_cpuid_version_set_stepping, NULL, NULL, NULL);
+ x86_cpuid_version_set_stepping, NULL, NULL);
object_property_add_str(obj, "vendor",
x86_cpuid_get_vendor,
- x86_cpuid_set_vendor, NULL);
+ x86_cpuid_set_vendor);
object_property_add_str(obj, "model-id",
x86_cpuid_get_model_id,
- x86_cpuid_set_model_id, NULL);
+ x86_cpuid_set_model_id);
object_property_add(obj, "tsc-frequency", "int",
x86_cpuid_get_tsc_freq,
- x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
+ x86_cpuid_set_tsc_freq, NULL, NULL);
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
x86_cpu_get_feature_words,
- NULL, NULL, (void *)env->features, NULL);
+ NULL, NULL, (void *)env->features);
object_property_add(obj, "filtered-features", "X86CPUFeatureWordInfo",
x86_cpu_get_feature_words,
- NULL, NULL, (void *)cpu->filtered_features, NULL);
+ NULL, NULL, (void *)cpu->filtered_features);
/*
* The "unavailable-features" property has the same semantics as
* CpuDefinitionInfo.unavailable-features on the "query-cpu-definitions"
*/
object_property_add(obj, "unavailable-features", "strList",
x86_cpu_get_unavailable_features,
- NULL, NULL, NULL, &error_abort);
+ NULL, NULL, NULL);
+#if !defined(CONFIG_USER_ONLY)
object_property_add(obj, "crash-information", "GuestPanicInformation",
- x86_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL);
+ x86_cpu_get_crash_info_qom, NULL, NULL, NULL);
+#endif
for (w = 0; w < FEATURE_WORDS; w++) {
int bitnr;
}
}
- object_property_add_alias(obj, "sse3", obj, "pni", &error_abort);
- object_property_add_alias(obj, "pclmuldq", obj, "pclmulqdq", &error_abort);
- object_property_add_alias(obj, "sse4-1", obj, "sse4.1", &error_abort);
- object_property_add_alias(obj, "sse4-2", obj, "sse4.2", &error_abort);
- object_property_add_alias(obj, "xd", obj, "nx", &error_abort);
- object_property_add_alias(obj, "ffxsr", obj, "fxsr-opt", &error_abort);
- object_property_add_alias(obj, "i64", obj, "lm", &error_abort);
-
- object_property_add_alias(obj, "ds_cpl", obj, "ds-cpl", &error_abort);
- object_property_add_alias(obj, "tsc_adjust", obj, "tsc-adjust", &error_abort);
- object_property_add_alias(obj, "fxsr_opt", obj, "fxsr-opt", &error_abort);
- object_property_add_alias(obj, "lahf_lm", obj, "lahf-lm", &error_abort);
- object_property_add_alias(obj, "cmp_legacy", obj, "cmp-legacy", &error_abort);
- object_property_add_alias(obj, "nodeid_msr", obj, "nodeid-msr", &error_abort);
- object_property_add_alias(obj, "perfctr_core", obj, "perfctr-core", &error_abort);
- object_property_add_alias(obj, "perfctr_nb", obj, "perfctr-nb", &error_abort);
- object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay", &error_abort);
- object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu", &error_abort);
- object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf", &error_abort);
- object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time", &error_abort);
- object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi", &error_abort);
- object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt", &error_abort);
- object_property_add_alias(obj, "kvm_poll_control", obj, "kvm-poll-control",
- &error_abort);
- object_property_add_alias(obj, "svm_lock", obj, "svm-lock", &error_abort);
- object_property_add_alias(obj, "nrip_save", obj, "nrip-save", &error_abort);
- object_property_add_alias(obj, "tsc_scale", obj, "tsc-scale", &error_abort);
- object_property_add_alias(obj, "vmcb_clean", obj, "vmcb-clean", &error_abort);
- object_property_add_alias(obj, "pause_filter", obj, "pause-filter", &error_abort);
- object_property_add_alias(obj, "sse4_1", obj, "sse4.1", &error_abort);
- object_property_add_alias(obj, "sse4_2", obj, "sse4.2", &error_abort);
+ object_property_add_alias(obj, "sse3", obj, "pni");
+ object_property_add_alias(obj, "pclmuldq", obj, "pclmulqdq");
+ object_property_add_alias(obj, "sse4-1", obj, "sse4.1");
+ object_property_add_alias(obj, "sse4-2", obj, "sse4.2");
+ object_property_add_alias(obj, "xd", obj, "nx");
+ object_property_add_alias(obj, "ffxsr", obj, "fxsr-opt");
+ object_property_add_alias(obj, "i64", obj, "lm");
+
+ object_property_add_alias(obj, "ds_cpl", obj, "ds-cpl");
+ object_property_add_alias(obj, "tsc_adjust", obj, "tsc-adjust");
+ object_property_add_alias(obj, "fxsr_opt", obj, "fxsr-opt");
+ object_property_add_alias(obj, "lahf_lm", obj, "lahf-lm");
+ object_property_add_alias(obj, "cmp_legacy", obj, "cmp-legacy");
+ object_property_add_alias(obj, "nodeid_msr", obj, "nodeid-msr");
+ object_property_add_alias(obj, "perfctr_core", obj, "perfctr-core");
+ object_property_add_alias(obj, "perfctr_nb", obj, "perfctr-nb");
+ object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay");
+ object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu");
+ object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf");
+ object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time");
+ object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi");
+ object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt");
+ object_property_add_alias(obj, "kvm_poll_control", obj, "kvm-poll-control");
+ object_property_add_alias(obj, "svm_lock", obj, "svm-lock");
+ object_property_add_alias(obj, "nrip_save", obj, "nrip-save");
+ object_property_add_alias(obj, "tsc_scale", obj, "tsc-scale");
+ object_property_add_alias(obj, "vmcb_clean", obj, "vmcb-clean");
+ object_property_add_alias(obj, "pause_filter", obj, "pause-filter");
+ object_property_add_alias(obj, "sse4_1", obj, "sse4.1");
+ object_property_add_alias(obj, "sse4_2", obj, "sse4.2");
if (xcc->model) {
- x86_cpu_load_model(cpu, xcc->model, &error_abort);
+ x86_cpu_load_model(cpu, xcc->model);
}
}
&xcc->parent_unrealize);
device_class_set_props(dc, x86_cpu_properties);
- cpu_class_set_parent_reset(cc, x86_cpu_reset, &xcc->parent_reset);
+ device_class_set_parent_reset(dc, x86_cpu_reset, &xcc->parent_reset);
cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP;
cc->class_by_name = x86_cpu_class_by_name;
cc->cpu_exec_interrupt = x86_cpu_exec_interrupt;
#endif
cc->dump_state = x86_cpu_dump_state;
- cc->get_crash_info = x86_cpu_get_crash_info;
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->asidx_from_attrs = x86_asidx_from_attrs;
cc->get_memory_mapping = x86_cpu_get_memory_mapping;
cc->get_phys_page_attrs_debug = x86_cpu_get_phys_page_attrs_debug;
+ cc->get_crash_info = x86_cpu_get_crash_info;
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;