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