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/xen.h"
23 #include "sysemu/whpx.h"
24 #include "kvm/kvm_i386.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 * writeable 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
,
192 qobject_to(QDict
, model
->props
) :
199 ret
->model
= g_new0(CpuModelInfo
, 1);
200 ret
->model
->props
= QOBJECT(props
);
201 ret
->model
->has_props
= true;
204 case CPU_MODEL_EXPANSION_TYPE_STATIC
:
205 /* Static expansion will be based on "base" only */
207 x86_cpu_to_dict(xc
, props
);
209 case CPU_MODEL_EXPANSION_TYPE_FULL
:
210 /* As we don't return every single property, full expansion needs
211 * to keep the original model name+props, and add extra
212 * properties on top of that.
214 base_name
= model
->name
;
215 x86_cpu_to_dict_full(xc
, props
);
218 error_setg(&err
, "Unsupported expansion type");
222 x86_cpu_to_dict(xc
, props
);
224 ret
->model
->name
= g_strdup(base_name
);
227 object_unref(OBJECT(xc
));
229 error_propagate(errp
, err
);
230 qapi_free_CpuModelExpansionInfo(ret
);
236 void cpu_clear_apic_feature(CPUX86State
*env
)
238 env
->features
[FEAT_1_EDX
] &= ~CPUID_APIC
;
241 bool cpu_is_bsp(X86CPU
*cpu
)
243 return cpu_get_apic_base(cpu
->apic_state
) & MSR_IA32_APICBASE_BSP
;
246 /* TODO: remove me, when reset over QOM tree is implemented */
247 void x86_cpu_machine_reset_cb(void *opaque
)
249 X86CPU
*cpu
= opaque
;
253 APICCommonClass
*apic_get_class(void)
255 const char *apic_type
= "apic";
257 /* TODO: in-kernel irqchip for hvf */
258 if (kvm_apic_in_kernel()) {
259 apic_type
= "kvm-apic";
260 } else if (xen_enabled()) {
261 apic_type
= "xen-apic";
262 } else if (whpx_apic_in_platform()) {
263 apic_type
= "whpx-apic";
266 return APIC_COMMON_CLASS(object_class_by_name(apic_type
));
269 void x86_cpu_apic_create(X86CPU
*cpu
, Error
**errp
)
271 APICCommonState
*apic
;
272 ObjectClass
*apic_class
= OBJECT_CLASS(apic_get_class());
274 cpu
->apic_state
= DEVICE(object_new_with_class(apic_class
));
276 object_property_add_child(OBJECT(cpu
), "lapic",
277 OBJECT(cpu
->apic_state
));
278 object_unref(OBJECT(cpu
->apic_state
));
280 qdev_prop_set_uint32(cpu
->apic_state
, "id", cpu
->apic_id
);
281 /* TODO: convert to link<> */
282 apic
= APIC_COMMON(cpu
->apic_state
);
284 apic
->apicbase
= APIC_DEFAULT_ADDRESS
| MSR_IA32_APICBASE_ENABLE
;
287 void x86_cpu_apic_realize(X86CPU
*cpu
, Error
**errp
)
289 APICCommonState
*apic
;
290 static bool apic_mmio_map_once
;
292 if (cpu
->apic_state
== NULL
) {
295 qdev_realize(DEVICE(cpu
->apic_state
), NULL
, errp
);
297 /* Map APIC MMIO area */
298 apic
= APIC_COMMON(cpu
->apic_state
);
299 if (!apic_mmio_map_once
) {
300 memory_region_add_subregion_overlap(get_system_memory(),
302 MSR_IA32_APICBASE_BASE
,
305 apic_mmio_map_once
= true;
309 GuestPanicInformation
*x86_cpu_get_crash_info(CPUState
*cs
)
311 X86CPU
*cpu
= X86_CPU(cs
);
312 CPUX86State
*env
= &cpu
->env
;
313 GuestPanicInformation
*panic_info
= NULL
;
315 if (hyperv_feat_enabled(cpu
, HYPERV_FEAT_CRASH
)) {
316 panic_info
= g_malloc0(sizeof(GuestPanicInformation
));
318 panic_info
->type
= GUEST_PANIC_INFORMATION_TYPE_HYPER_V
;
320 assert(HV_CRASH_PARAMS
>= 5);
321 panic_info
->u
.hyper_v
.arg1
= env
->msr_hv_crash_params
[0];
322 panic_info
->u
.hyper_v
.arg2
= env
->msr_hv_crash_params
[1];
323 panic_info
->u
.hyper_v
.arg3
= env
->msr_hv_crash_params
[2];
324 panic_info
->u
.hyper_v
.arg4
= env
->msr_hv_crash_params
[3];
325 panic_info
->u
.hyper_v
.arg5
= env
->msr_hv_crash_params
[4];
330 void x86_cpu_get_crash_info_qom(Object
*obj
, Visitor
*v
,
331 const char *name
, void *opaque
,
334 CPUState
*cs
= CPU(obj
);
335 GuestPanicInformation
*panic_info
;
337 if (!cs
->crash_occurred
) {
338 error_setg(errp
, "No crash occurred");
342 panic_info
= x86_cpu_get_crash_info(cs
);
343 if (panic_info
== NULL
) {
344 error_setg(errp
, "No crash information");
348 visit_type_GuestPanicInformation(v
, "crash-information", &panic_info
,
350 qapi_free_GuestPanicInformation(panic_info
);