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

s390-stattrib.c (11603B)


      1/*
      2 * s390 storage attributes device
      3 *
      4 * Copyright 2016 IBM Corp.
      5 * Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
      6 *
      7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
      8 * your option) any later version. See the COPYING file in the top-level
      9 * directory.
     10 */
     11
     12#include "qemu/osdep.h"
     13#include "qemu/units.h"
     14#include "migration/qemu-file.h"
     15#include "migration/register.h"
     16#include "hw/s390x/storage-attributes.h"
     17#include "qemu/error-report.h"
     18#include "exec/ram_addr.h"
     19#include "qapi/error.h"
     20#include "qapi/qmp/qdict.h"
     21
     22/* 512KiB cover 2GB of guest memory */
     23#define CMMA_BLOCK_SIZE  (512 * KiB)
     24
     25#define STATTR_FLAG_EOS     0x01ULL
     26#define STATTR_FLAG_MORE    0x02ULL
     27#define STATTR_FLAG_ERROR   0x04ULL
     28#define STATTR_FLAG_DONE    0x08ULL
     29
     30static S390StAttribState *s390_get_stattrib_device(void)
     31{
     32    S390StAttribState *sas;
     33
     34    sas = S390_STATTRIB(object_resolve_path_type("", TYPE_S390_STATTRIB, NULL));
     35    assert(sas);
     36    return sas;
     37}
     38
     39void s390_stattrib_init(void)
     40{
     41    Object *obj;
     42
     43    obj = kvm_s390_stattrib_create();
     44    if (!obj) {
     45        obj = object_new(TYPE_QEMU_S390_STATTRIB);
     46    }
     47
     48    object_property_add_child(qdev_get_machine(), TYPE_S390_STATTRIB,
     49                              obj);
     50    object_unref(obj);
     51
     52    qdev_realize(DEVICE(obj), NULL, &error_fatal);
     53}
     54
     55/* Console commands: */
     56
     57void hmp_migrationmode(Monitor *mon, const QDict *qdict)
     58{
     59    S390StAttribState *sas = s390_get_stattrib_device();
     60    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
     61    uint64_t what = qdict_get_int(qdict, "mode");
     62    int r;
     63
     64    r = sac->set_migrationmode(sas, what);
     65    if (r < 0) {
     66        monitor_printf(mon, "Error: %s", strerror(-r));
     67    }
     68}
     69
     70void hmp_info_cmma(Monitor *mon, const QDict *qdict)
     71{
     72    S390StAttribState *sas = s390_get_stattrib_device();
     73    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
     74    uint64_t addr = qdict_get_int(qdict, "addr");
     75    uint64_t buflen = qdict_get_try_int(qdict, "count", 8);
     76    uint8_t *vals;
     77    int cx, len;
     78
     79    vals = g_try_malloc(buflen);
     80    if (!vals) {
     81        monitor_printf(mon, "Error: %s\n", strerror(errno));
     82        return;
     83    }
     84
     85    len = sac->peek_stattr(sas, addr / TARGET_PAGE_SIZE, buflen, vals);
     86    if (len < 0) {
     87        monitor_printf(mon, "Error: %s", strerror(-len));
     88        goto out;
     89    }
     90
     91    monitor_printf(mon, "  CMMA attributes, "
     92                   "pages %" PRIu64 "+%d (0x%" PRIx64 "):\n",
     93                   addr / TARGET_PAGE_SIZE, len, addr & ~TARGET_PAGE_MASK);
     94    for (cx = 0; cx < len; cx++) {
     95        if (cx % 8 == 7) {
     96            monitor_printf(mon, "%02x\n", vals[cx]);
     97        } else {
     98            monitor_printf(mon, "%02x", vals[cx]);
     99        }
    100    }
    101    monitor_printf(mon, "\n");
    102
    103out:
    104    g_free(vals);
    105}
    106
    107/* Migration support: */
    108
    109static int cmma_load(QEMUFile *f, void *opaque, int version_id)
    110{
    111    S390StAttribState *sas = S390_STATTRIB(opaque);
    112    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
    113    uint64_t count, cur_gfn;
    114    int flags, ret = 0;
    115    ram_addr_t addr;
    116    uint8_t *buf;
    117
    118    while (!ret) {
    119        addr = qemu_get_be64(f);
    120        flags = addr & ~TARGET_PAGE_MASK;
    121        addr &= TARGET_PAGE_MASK;
    122
    123        switch (flags) {
    124        case STATTR_FLAG_MORE: {
    125            cur_gfn = addr / TARGET_PAGE_SIZE;
    126            count = qemu_get_be64(f);
    127            buf = g_try_malloc(count);
    128            if (!buf) {
    129                error_report("cmma_load could not allocate memory");
    130                ret = -ENOMEM;
    131                break;
    132            }
    133
    134            qemu_get_buffer(f, buf, count);
    135            ret = sac->set_stattr(sas, cur_gfn, count, buf);
    136            if (ret < 0) {
    137                error_report("Error %d while setting storage attributes", ret);
    138            }
    139            g_free(buf);
    140            break;
    141        }
    142        case STATTR_FLAG_ERROR: {
    143            error_report("Storage attributes data is incomplete");
    144            ret = -EINVAL;
    145            break;
    146        }
    147        case STATTR_FLAG_DONE:
    148            /* This is after the last pre-copied value has been sent, nothing
    149             * more will be sent after this. Pre-copy has finished, and we
    150             * are done flushing all the remaining values. Now the target
    151             * system is about to take over. We synchronize the buffer to
    152             * apply the actual correct values where needed.
    153             */
    154             sac->synchronize(sas);
    155            break;
    156        case STATTR_FLAG_EOS:
    157            /* Normal exit */
    158            return 0;
    159        default:
    160            error_report("Unexpected storage attribute flag data: %#x", flags);
    161            ret = -EINVAL;
    162        }
    163    }
    164
    165    return ret;
    166}
    167
    168static int cmma_save_setup(QEMUFile *f, void *opaque)
    169{
    170    S390StAttribState *sas = S390_STATTRIB(opaque);
    171    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
    172    int res;
    173    /*
    174     * Signal that we want to start a migration, thus needing PGSTE dirty
    175     * tracking.
    176     */
    177    res = sac->set_migrationmode(sas, 1);
    178    if (res) {
    179        return res;
    180    }
    181    qemu_put_be64(f, STATTR_FLAG_EOS);
    182    return 0;
    183}
    184
    185static void cmma_save_pending(QEMUFile *f, void *opaque, uint64_t max_size,
    186                              uint64_t *res_precopy_only,
    187                              uint64_t *res_compatible,
    188                              uint64_t *res_postcopy_only)
    189{
    190    S390StAttribState *sas = S390_STATTRIB(opaque);
    191    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
    192    long long res = sac->get_dirtycount(sas);
    193
    194    if (res >= 0) {
    195        *res_precopy_only += res;
    196    }
    197}
    198
    199static int cmma_save(QEMUFile *f, void *opaque, int final)
    200{
    201    S390StAttribState *sas = S390_STATTRIB(opaque);
    202    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
    203    uint8_t *buf;
    204    int r, cx, reallen = 0, ret = 0;
    205    uint32_t buflen = CMMA_BLOCK_SIZE;
    206    uint64_t start_gfn = sas->migration_cur_gfn;
    207
    208    buf = g_try_malloc(buflen);
    209    if (!buf) {
    210        error_report("Could not allocate memory to save storage attributes");
    211        return -ENOMEM;
    212    }
    213
    214    while (final ? 1 : qemu_file_rate_limit(f) == 0) {
    215        reallen = sac->get_stattr(sas, &start_gfn, buflen, buf);
    216        if (reallen < 0) {
    217            g_free(buf);
    218            return reallen;
    219        }
    220
    221        ret = 1;
    222        if (!reallen) {
    223            break;
    224        }
    225        qemu_put_be64(f, (start_gfn << TARGET_PAGE_BITS) | STATTR_FLAG_MORE);
    226        qemu_put_be64(f, reallen);
    227        for (cx = 0; cx < reallen; cx++) {
    228            qemu_put_byte(f, buf[cx]);
    229        }
    230        if (!sac->get_dirtycount(sas)) {
    231            break;
    232        }
    233    }
    234
    235    sas->migration_cur_gfn = start_gfn + reallen;
    236    g_free(buf);
    237    if (final) {
    238        qemu_put_be64(f, STATTR_FLAG_DONE);
    239    }
    240    qemu_put_be64(f, STATTR_FLAG_EOS);
    241
    242    r = qemu_file_get_error(f);
    243    if (r < 0) {
    244        return r;
    245    }
    246
    247    return ret;
    248}
    249
    250static int cmma_save_iterate(QEMUFile *f, void *opaque)
    251{
    252    return cmma_save(f, opaque, 0);
    253}
    254
    255static int cmma_save_complete(QEMUFile *f, void *opaque)
    256{
    257    return cmma_save(f, opaque, 1);
    258}
    259
    260static void cmma_save_cleanup(void *opaque)
    261{
    262    S390StAttribState *sas = S390_STATTRIB(opaque);
    263    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
    264    sac->set_migrationmode(sas, 0);
    265}
    266
    267static bool cmma_active(void *opaque)
    268{
    269    S390StAttribState *sas = S390_STATTRIB(opaque);
    270    S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
    271    return sac->get_active(sas);
    272}
    273
    274/* QEMU object: */
    275
    276static void qemu_s390_stattrib_instance_init(Object *obj)
    277{
    278}
    279
    280static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn,
    281                                     uint32_t count, uint8_t *values)
    282{
    283    return 0;
    284}
    285static void qemu_s390_synchronize_stub(S390StAttribState *sa)
    286{
    287}
    288static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn,
    289                                     uint32_t count, uint8_t *values)
    290{
    291    return 0;
    292}
    293static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa)
    294{
    295    return 0;
    296}
    297static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value)
    298{
    299    return 0;
    300}
    301
    302static int qemu_s390_get_active(S390StAttribState *sa)
    303{
    304    return sa->migration_enabled;
    305}
    306
    307static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data)
    308{
    309    S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc);
    310    DeviceClass *dc = DEVICE_CLASS(oc);
    311
    312    sa_cl->synchronize = qemu_s390_synchronize_stub;
    313    sa_cl->get_stattr = qemu_s390_get_stattr_stub;
    314    sa_cl->set_stattr = qemu_s390_peek_stattr_stub;
    315    sa_cl->peek_stattr = qemu_s390_peek_stattr_stub;
    316    sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub;
    317    sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub;
    318    sa_cl->get_active = qemu_s390_get_active;
    319
    320    /* Reason: Can only be instantiated one time (internally) */
    321    dc->user_creatable = false;
    322}
    323
    324static const TypeInfo qemu_s390_stattrib_info = {
    325    .name          = TYPE_QEMU_S390_STATTRIB,
    326    .parent        = TYPE_S390_STATTRIB,
    327    .instance_init = qemu_s390_stattrib_instance_init,
    328    .instance_size = sizeof(QEMUS390StAttribState),
    329    .class_init    = qemu_s390_stattrib_class_init,
    330    .class_size    = sizeof(S390StAttribClass),
    331};
    332
    333/* Generic abstract object: */
    334
    335static void s390_stattrib_realize(DeviceState *dev, Error **errp)
    336{
    337    bool ambiguous = false;
    338
    339    object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous);
    340    if (ambiguous) {
    341        error_setg(errp, "storage_attributes device already exists");
    342    }
    343}
    344
    345static void s390_stattrib_class_init(ObjectClass *oc, void *data)
    346{
    347    DeviceClass *dc = DEVICE_CLASS(oc);
    348
    349    dc->hotpluggable = false;
    350    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    351    dc->realize = s390_stattrib_realize;
    352}
    353
    354static inline bool s390_stattrib_get_migration_enabled(Object *obj,
    355                                                       Error **errp)
    356{
    357    S390StAttribState *s = S390_STATTRIB(obj);
    358
    359    return s->migration_enabled;
    360}
    361
    362static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value,
    363                                            Error **errp)
    364{
    365    S390StAttribState *s = S390_STATTRIB(obj);
    366
    367    s->migration_enabled = value;
    368}
    369
    370static SaveVMHandlers savevm_s390_stattrib_handlers = {
    371    .save_setup = cmma_save_setup,
    372    .save_live_iterate = cmma_save_iterate,
    373    .save_live_complete_precopy = cmma_save_complete,
    374    .save_live_pending = cmma_save_pending,
    375    .save_cleanup = cmma_save_cleanup,
    376    .load_state = cmma_load,
    377    .is_active = cmma_active,
    378};
    379
    380static void s390_stattrib_instance_init(Object *obj)
    381{
    382    S390StAttribState *sas = S390_STATTRIB(obj);
    383
    384    register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
    385                         &savevm_s390_stattrib_handlers, sas);
    386
    387    object_property_add_bool(obj, "migration-enabled",
    388                             s390_stattrib_get_migration_enabled,
    389                             s390_stattrib_set_migration_enabled);
    390    object_property_set_bool(obj, "migration-enabled", true, NULL);
    391    sas->migration_cur_gfn = 0;
    392}
    393
    394static const TypeInfo s390_stattrib_info = {
    395    .name          = TYPE_S390_STATTRIB,
    396    .parent        = TYPE_DEVICE,
    397    .instance_init = s390_stattrib_instance_init,
    398    .instance_size = sizeof(S390StAttribState),
    399    .class_init    = s390_stattrib_class_init,
    400    .class_size    = sizeof(S390StAttribClass),
    401    .abstract      = true,
    402};
    403
    404static void s390_stattrib_register_types(void)
    405{
    406    type_register_static(&s390_stattrib_info);
    407    type_register_static(&qemu_s390_stattrib_info);
    408}
    409
    410type_init(s390_stattrib_register_types)