2 * i386 CPUID, CPU class, definitions, models: sysemu-only code
4 * Copyright (c) 2003 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
22 #include "sysemu/kvm.h"
23 #include "sysemu/xen.h"
24 #include "sysemu/whpx.h"
25 #include "qapi/error.h"
26 #include "qapi/qapi-visit-run-state.h"
27 #include "qapi/qmp/qdict.h"
28 #include "qom/qom-qobject.h"
29 #include "qapi/qapi-commands-machine-target.h"
30 #include "hw/qdev-properties.h"
32 #include "exec/address-spaces.h"
33 #include "hw/i386/apic_internal.h"
35 #include "cpu-internal.h"
37 /* Return a QDict containing keys for all properties that can be included
38 * in static expansion of CPU models. All properties set by x86_cpu_load_model()
39 * must be included in the dictionary.
41 static QDict
*x86_cpu_static_props(void)
45 static const char *props
[] = {
63 for (i
= 0; props
[i
]; i
++) {
64 qdict_put_null(d
, props
[i
]);
67 for (w
= 0; w
< FEATURE_WORDS
; w
++) {
68 FeatureWordInfo
*fi
= &feature_word_info
[w
];
70 for (bit
= 0; bit
< 64; bit
++) {
71 if (!fi
->feat_names
[bit
]) {
74 qdict_put_null(d
, fi
->feat_names
[bit
]);
81 /* Add an entry to @props dict, with the value for property. */
82 static void x86_cpu_expand_prop(X86CPU
*cpu
, QDict
*props
, const char *prop
)
84 QObject
*value
= object_property_get_qobject(OBJECT(cpu
), prop
,
87 qdict_put_obj(props
, prop
, value
);
90 /* Convert CPU model data from X86CPU object to a property dictionary
91 * that can recreate exactly the same CPU model.
93 static void x86_cpu_to_dict(X86CPU
*cpu
, QDict
*props
)
95 QDict
*sprops
= x86_cpu_static_props();
98 for (e
= qdict_first(sprops
); e
; e
= qdict_next(sprops
, e
)) {
99 const char *prop
= qdict_entry_key(e
);
100 x86_cpu_expand_prop(cpu
, props
, prop
);
104 /* Convert CPU model data from X86CPU object to a property dictionary
105 * that can recreate exactly the same CPU model, including every
106 * writable QOM property.
108 static void x86_cpu_to_dict_full(X86CPU
*cpu
, QDict
*props
)
110 ObjectPropertyIterator iter
;
111 ObjectProperty
*prop
;
113 object_property_iter_init(&iter
, OBJECT(cpu
));
114 while ((prop
= object_property_iter_next(&iter
))) {
115 /* skip read-only or write-only properties */
116 if (!prop
->get
|| !prop
->set
) {
120 /* "hotplugged" is the only property that is configurable
121 * on the command-line but will be set differently on CPUs
122 * created using "-cpu ... -smp ..." and by CPUs created
123 * on the fly by x86_cpu_from_model() for querying. Skip it.
125 if (!strcmp(prop
->name
, "hotplugged")) {
128 x86_cpu_expand_prop(cpu
, props
, prop
->name
);
132 static void object_apply_props(Object
*obj
, QDict
*props
, Error
**errp
)
134 const QDictEntry
*prop
;
136 for (prop
= qdict_first(props
); prop
; prop
= qdict_next(props
, prop
)) {
137 if (!object_property_set_qobject(obj
, qdict_entry_key(prop
),
138 qdict_entry_value(prop
), errp
)) {
144 /* Create X86CPU object according to model+props specification */
145 static X86CPU
*x86_cpu_from_model(const char *model
, QDict
*props
, Error
**errp
)
151 xcc
= X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU
, model
));
153 error_setg(&err
, "CPU model '%s' not found", model
);
157 xc
= X86_CPU(object_new_with_class(OBJECT_CLASS(xcc
)));
159 object_apply_props(OBJECT(xc
), props
, &err
);
165 x86_cpu_expand_features(xc
, &err
);
172 error_propagate(errp
, err
);
173 object_unref(OBJECT(xc
));
179 CpuModelExpansionInfo
*
180 qmp_query_cpu_model_expansion(CpuModelExpansionType type
,
186 CpuModelExpansionInfo
*ret
= g_new0(CpuModelExpansionInfo
, 1);
188 const char *base_name
;
190 xc
= x86_cpu_from_model(model
->name
, qobject_to(QDict
, model
->props
),
197 ret
->model
= g_new0(CpuModelInfo
, 1);
198 ret
->model
->props
= QOBJECT(props
);
201 case CPU_MODEL_EXPANSION_TYPE_STATIC
:
202 /* Static expansion will be based on "base" only */
204 x86_cpu_to_dict(xc
, props
);
206 case CPU_MODEL_EXPANSION_TYPE_FULL
:
207 /* As we don't return every single property, full expansion needs
208 * to keep the original model name+props, and add extra
209 * properties on top of that.
211 base_name
= model
->name
;
212 x86_cpu_to_dict_full(xc
, props
);
215 error_setg(&err
, "Unsupported expansion type");
219 x86_cpu_to_dict(xc
, props
);
221 ret
->model
->name
= g_strdup(base_name
);
224 object_unref(OBJECT(xc
));
226 error_propagate(errp
, err
);
227 qapi_free_CpuModelExpansionInfo(ret
);
233 void cpu_clear_apic_feature(CPUX86State
*env
)
235 env
->features
[FEAT_1_EDX
] &= ~CPUID_APIC
;
238 void cpu_set_apic_feature(CPUX86State
*env
)
240 env
->features
[FEAT_1_EDX
] |= CPUID_APIC
;
243 bool cpu_has_x2apic_feature(CPUX86State
*env
)
245 return env
->features
[FEAT_1_ECX
] & CPUID_EXT_X2APIC
;
248 bool cpu_is_bsp(X86CPU
*cpu
)
250 return cpu_get_apic_base(cpu
->apic_state
) & MSR_IA32_APICBASE_BSP
;
253 /* TODO: remove me, when reset over QOM tree is implemented */
254 void x86_cpu_machine_reset_cb(void *opaque
)
256 X86CPU
*cpu
= opaque
;
260 APICCommonClass
*apic_get_class(Error
**errp
)
262 const char *apic_type
= "apic";
264 /* TODO: in-kernel irqchip for hvf */
266 if (!kvm_irqchip_in_kernel()) {
267 error_setg(errp
, "KVM does not support userspace APIC");
270 apic_type
= "kvm-apic";
271 } else if (xen_enabled()) {
272 apic_type
= "xen-apic";
273 } else if (whpx_apic_in_platform()) {
274 apic_type
= "whpx-apic";
277 return APIC_COMMON_CLASS(object_class_by_name(apic_type
));
280 void x86_cpu_apic_create(X86CPU
*cpu
, Error
**errp
)
282 APICCommonState
*apic
;
283 APICCommonClass
*apic_class
= apic_get_class(errp
);
289 cpu
->apic_state
= DEVICE(object_new_with_class(OBJECT_CLASS(apic_class
)));
290 object_property_add_child(OBJECT(cpu
), "lapic",
291 OBJECT(cpu
->apic_state
));
292 object_unref(OBJECT(cpu
->apic_state
));
294 /* TODO: convert to link<> */
295 apic
= APIC_COMMON(cpu
->apic_state
);
297 apic
->apicbase
= APIC_DEFAULT_ADDRESS
| MSR_IA32_APICBASE_ENABLE
;
300 * apic_common_set_id needs to check if the CPU has x2APIC
301 * feature in case APIC ID >= 255, so we need to set apic->cpu
302 * before setting APIC ID
304 qdev_prop_set_uint32(cpu
->apic_state
, "id", cpu
->apic_id
);
307 void x86_cpu_apic_realize(X86CPU
*cpu
, Error
**errp
)
309 APICCommonState
*apic
;
310 static bool apic_mmio_map_once
;
312 if (cpu
->apic_state
== NULL
) {
315 qdev_realize(DEVICE(cpu
->apic_state
), NULL
, errp
);
317 /* Map APIC MMIO area */
318 apic
= APIC_COMMON(cpu
->apic_state
);
319 if (!apic_mmio_map_once
) {
320 memory_region_add_subregion_overlap(get_system_memory(),
322 MSR_IA32_APICBASE_BASE
,
325 apic_mmio_map_once
= true;
329 GuestPanicInformation
*x86_cpu_get_crash_info(CPUState
*cs
)
331 X86CPU
*cpu
= X86_CPU(cs
);
332 CPUX86State
*env
= &cpu
->env
;
333 GuestPanicInformation
*panic_info
= NULL
;
335 if (hyperv_feat_enabled(cpu
, HYPERV_FEAT_CRASH
)) {
336 panic_info
= g_new0(GuestPanicInformation
, 1);
338 panic_info
->type
= GUEST_PANIC_INFORMATION_TYPE_HYPER_V
;
340 assert(HV_CRASH_PARAMS
>= 5);
341 panic_info
->u
.hyper_v
.arg1
= env
->msr_hv_crash_params
[0];
342 panic_info
->u
.hyper_v
.arg2
= env
->msr_hv_crash_params
[1];
343 panic_info
->u
.hyper_v
.arg3
= env
->msr_hv_crash_params
[2];
344 panic_info
->u
.hyper_v
.arg4
= env
->msr_hv_crash_params
[3];
345 panic_info
->u
.hyper_v
.arg5
= env
->msr_hv_crash_params
[4];
350 void x86_cpu_get_crash_info_qom(Object
*obj
, Visitor
*v
,
351 const char *name
, void *opaque
,
354 CPUState
*cs
= CPU(obj
);
355 GuestPanicInformation
*panic_info
;
357 if (!cs
->crash_occurred
) {
358 error_setg(errp
, "No crash occurred");
362 panic_info
= x86_cpu_get_crash_info(cs
);
363 if (panic_info
== NULL
) {
364 error_setg(errp
, "No crash information");
368 visit_type_GuestPanicInformation(v
, "crash-information", &panic_info
,
370 qapi_free_GuestPanicInformation(panic_info
);