qemu/target/i386/cpu-sysemu.c
<<
>>
Prefs
   1/*
   2 *  i386 CPUID, CPU class, definitions, models: sysemu-only code
   3 *
   4 *  Copyright (c) 2003 Fabrice Bellard
   5 *
   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.
  10 *
  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.
  15 *
  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/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "cpu.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"
  31
  32#include "exec/address-spaces.h"
  33#include "hw/i386/apic_internal.h"
  34
  35#include "cpu-internal.h"
  36
  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.
  40 */
  41static QDict *x86_cpu_static_props(void)
  42{
  43    FeatureWord w;
  44    int i;
  45    static const char *props[] = {
  46        "min-level",
  47        "min-xlevel",
  48        "family",
  49        "model",
  50        "stepping",
  51        "model-id",
  52        "vendor",
  53        "lmce",
  54        NULL,
  55    };
  56    static QDict *d;
  57
  58    if (d) {
  59        return d;
  60    }
  61
  62    d = qdict_new();
  63    for (i = 0; props[i]; i++) {
  64        qdict_put_null(d, props[i]);
  65    }
  66
  67    for (w = 0; w < FEATURE_WORDS; w++) {
  68        FeatureWordInfo *fi = &feature_word_info[w];
  69        int bit;
  70        for (bit = 0; bit < 64; bit++) {
  71            if (!fi->feat_names[bit]) {
  72                continue;
  73            }
  74            qdict_put_null(d, fi->feat_names[bit]);
  75        }
  76    }
  77
  78    return d;
  79}
  80
  81/* Add an entry to @props dict, with the value for property. */
  82static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop)
  83{
  84    QObject *value = object_property_get_qobject(OBJECT(cpu), prop,
  85                                                 &error_abort);
  86
  87    qdict_put_obj(props, prop, value);
  88}
  89
  90/* Convert CPU model data from X86CPU object to a property dictionary
  91 * that can recreate exactly the same CPU model.
  92 */
  93static void x86_cpu_to_dict(X86CPU *cpu, QDict *props)
  94{
  95    QDict *sprops = x86_cpu_static_props();
  96    const QDictEntry *e;
  97
  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);
 101    }
 102}
 103
 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.
 107 */
 108static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props)
 109{
 110    ObjectPropertyIterator iter;
 111    ObjectProperty *prop;
 112
 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) {
 117            continue;
 118        }
 119
 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.
 124         */
 125        if (!strcmp(prop->name, "hotplugged")) {
 126            continue;
 127        }
 128        x86_cpu_expand_prop(cpu, props, prop->name);
 129    }
 130}
 131
 132static void object_apply_props(Object *obj, QDict *props, Error **errp)
 133{
 134    const QDictEntry *prop;
 135
 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)) {
 139            break;
 140        }
 141    }
 142}
 143
 144/* Create X86CPU object according to model+props specification */
 145static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp)
 146{
 147    X86CPU *xc = NULL;
 148    X86CPUClass *xcc;
 149    Error *err = NULL;
 150
 151    xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model));
 152    if (xcc == NULL) {
 153        error_setg(&err, "CPU model '%s' not found", model);
 154        goto out;
 155    }
 156
 157    xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc)));
 158    if (props) {
 159        object_apply_props(OBJECT(xc), props, &err);
 160        if (err) {
 161            goto out;
 162        }
 163    }
 164
 165    x86_cpu_expand_features(xc, &err);
 166    if (err) {
 167        goto out;
 168    }
 169
 170out:
 171    if (err) {
 172        error_propagate(errp, err);
 173        object_unref(OBJECT(xc));
 174        xc = NULL;
 175    }
 176    return xc;
 177}
 178
 179CpuModelExpansionInfo *
 180qmp_query_cpu_model_expansion(CpuModelExpansionType type,
 181                                                      CpuModelInfo *model,
 182                                                      Error **errp)
 183{
 184    X86CPU *xc = NULL;
 185    Error *err = NULL;
 186    CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1);
 187    QDict *props = NULL;
 188    const char *base_name;
 189
 190    xc = x86_cpu_from_model(model->name,
 191                            model->has_props ?
 192                                qobject_to(QDict, model->props) :
 193                                NULL, &err);
 194    if (err) {
 195        goto out;
 196    }
 197
 198    props = qdict_new();
 199    ret->model = g_new0(CpuModelInfo, 1);
 200    ret->model->props = QOBJECT(props);
 201    ret->model->has_props = true;
 202
 203    switch (type) {
 204    case CPU_MODEL_EXPANSION_TYPE_STATIC:
 205        /* Static expansion will be based on "base" only */
 206        base_name = "base";
 207        x86_cpu_to_dict(xc, props);
 208    break;
 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.
 213         */
 214        base_name = model->name;
 215        x86_cpu_to_dict_full(xc, props);
 216    break;
 217    default:
 218        error_setg(&err, "Unsupported expansion type");
 219        goto out;
 220    }
 221
 222    x86_cpu_to_dict(xc, props);
 223
 224    ret->model->name = g_strdup(base_name);
 225
 226out:
 227    object_unref(OBJECT(xc));
 228    if (err) {
 229        error_propagate(errp, err);
 230        qapi_free_CpuModelExpansionInfo(ret);
 231        ret = NULL;
 232    }
 233    return ret;
 234}
 235
 236void cpu_clear_apic_feature(CPUX86State *env)
 237{
 238    env->features[FEAT_1_EDX] &= ~CPUID_APIC;
 239}
 240
 241bool cpu_is_bsp(X86CPU *cpu)
 242{
 243    return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP;
 244}
 245
 246/* TODO: remove me, when reset over QOM tree is implemented */
 247void x86_cpu_machine_reset_cb(void *opaque)
 248{
 249    X86CPU *cpu = opaque;
 250    cpu_reset(CPU(cpu));
 251}
 252
 253APICCommonClass *apic_get_class(void)
 254{
 255    const char *apic_type = "apic";
 256
 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";
 264    }
 265
 266    return APIC_COMMON_CLASS(object_class_by_name(apic_type));
 267}
 268
 269void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
 270{
 271    APICCommonState *apic;
 272    ObjectClass *apic_class = OBJECT_CLASS(apic_get_class());
 273
 274    cpu->apic_state = DEVICE(object_new_with_class(apic_class));
 275
 276    object_property_add_child(OBJECT(cpu), "lapic",
 277                              OBJECT(cpu->apic_state));
 278    object_unref(OBJECT(cpu->apic_state));
 279
 280    qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
 281    /* TODO: convert to link<> */
 282    apic = APIC_COMMON(cpu->apic_state);
 283    apic->cpu = cpu;
 284    apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
 285}
 286
 287void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
 288{
 289    APICCommonState *apic;
 290    static bool apic_mmio_map_once;
 291
 292    if (cpu->apic_state == NULL) {
 293        return;
 294    }
 295    qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
 296
 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(),
 301                                            apic->apicbase &
 302                                            MSR_IA32_APICBASE_BASE,
 303                                            &apic->io_memory,
 304                                            0x1000);
 305        apic_mmio_map_once = true;
 306     }
 307}
 308
 309GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
 310{
 311    X86CPU *cpu = X86_CPU(cs);
 312    CPUX86State *env = &cpu->env;
 313    GuestPanicInformation *panic_info = NULL;
 314
 315    if (hyperv_feat_enabled(cpu, HYPERV_FEAT_CRASH)) {
 316        panic_info = g_malloc0(sizeof(GuestPanicInformation));
 317
 318        panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V;
 319
 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];
 326    }
 327
 328    return panic_info;
 329}
 330void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v,
 331                                const char *name, void *opaque,
 332                                Error **errp)
 333{
 334    CPUState *cs = CPU(obj);
 335    GuestPanicInformation *panic_info;
 336
 337    if (!cs->crash_occurred) {
 338        error_setg(errp, "No crash occurred");
 339        return;
 340    }
 341
 342    panic_info = x86_cpu_get_crash_info(cs);
 343    if (panic_info == NULL) {
 344        error_setg(errp, "No crash information");
 345        return;
 346    }
 347
 348    visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
 349                                     errp);
 350    qapi_free_GuestPanicInformation(panic_info);
 351}
 352
 353