qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     30 static 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 
     39 void 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 
     57 void 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 
     70 void 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 
    103 out:
    104     g_free(vals);
    105 }
    106 
    107 /* Migration support: */
    108 
    109 static 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 
    168 static 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 
    185 static 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 
    199 static 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 
    250 static int cmma_save_iterate(QEMUFile *f, void *opaque)
    251 {
    252     return cmma_save(f, opaque, 0);
    253 }
    254 
    255 static int cmma_save_complete(QEMUFile *f, void *opaque)
    256 {
    257     return cmma_save(f, opaque, 1);
    258 }
    259 
    260 static 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 
    267 static 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 
    276 static void qemu_s390_stattrib_instance_init(Object *obj)
    277 {
    278 }
    279 
    280 static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn,
    281                                      uint32_t count, uint8_t *values)
    282 {
    283     return 0;
    284 }
    285 static void qemu_s390_synchronize_stub(S390StAttribState *sa)
    286 {
    287 }
    288 static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn,
    289                                      uint32_t count, uint8_t *values)
    290 {
    291     return 0;
    292 }
    293 static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa)
    294 {
    295     return 0;
    296 }
    297 static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value)
    298 {
    299     return 0;
    300 }
    301 
    302 static int qemu_s390_get_active(S390StAttribState *sa)
    303 {
    304     return sa->migration_enabled;
    305 }
    306 
    307 static 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 
    324 static 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 
    335 static 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 
    345 static 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 
    354 static 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 
    362 static 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 
    370 static 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 
    380 static 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 
    394 static 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 
    404 static void s390_stattrib_register_types(void)
    405 {
    406     type_register_static(&s390_stattrib_info);
    407     type_register_static(&qemu_s390_stattrib_info);
    408 }
    409 
    410 type_init(s390_stattrib_register_types)