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