cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

cpu-sysemu.c (10078B)


      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