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 31 static 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 40 void 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 58 void 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 71 void 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 104 out: 105 g_free(vals); 106 } 107 108 /* Migration support: */ 109 110 static 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 169 static 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 186 static 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 200 static 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 251 static int cmma_save_iterate(QEMUFile *f, void *opaque) 252 { 253 return cmma_save(f, opaque, 0); 254 } 255 256 static int cmma_save_complete(QEMUFile *f, void *opaque) 257 { 258 return cmma_save(f, opaque, 1); 259 } 260 261 static 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 268 static 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 277 static void qemu_s390_stattrib_instance_init(Object *obj) 278 { 279 } 280 281 static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn, 282 uint32_t count, uint8_t *values) 283 { 284 return 0; 285 } 286 static void qemu_s390_synchronize_stub(S390StAttribState *sa) 287 { 288 } 289 static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn, 290 uint32_t count, uint8_t *values) 291 { 292 return 0; 293 } 294 static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa) 295 { 296 return 0; 297 } 298 static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value) 299 { 300 return 0; 301 } 302 303 static int qemu_s390_get_active(S390StAttribState *sa) 304 { 305 return sa->migration_enabled; 306 } 307 308 static 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 325 static 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 336 static 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 346 static 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 355 static 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 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(NULL, 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 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) 411