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_state_pending(void *opaque, uint64_t *must_precopy, 186 uint64_t *can_postcopy) 187 { 188 S390StAttribState *sas = S390_STATTRIB(opaque); 189 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 190 long long res = sac->get_dirtycount(sas); 191 192 if (res >= 0) { 193 *must_precopy += res; 194 } 195 } 196 197 static int cmma_save(QEMUFile *f, void *opaque, int final) 198 { 199 S390StAttribState *sas = S390_STATTRIB(opaque); 200 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 201 uint8_t *buf; 202 int r, cx, reallen = 0, ret = 0; 203 uint32_t buflen = CMMA_BLOCK_SIZE; 204 uint64_t start_gfn = sas->migration_cur_gfn; 205 206 buf = g_try_malloc(buflen); 207 if (!buf) { 208 error_report("Could not allocate memory to save storage attributes"); 209 return -ENOMEM; 210 } 211 212 while (final ? 1 : migration_rate_exceeded(f) == 0) { 213 reallen = sac->get_stattr(sas, &start_gfn, buflen, buf); 214 if (reallen < 0) { 215 g_free(buf); 216 return reallen; 217 } 218 219 ret = 1; 220 if (!reallen) { 221 break; 222 } 223 qemu_put_be64(f, (start_gfn << TARGET_PAGE_BITS) | STATTR_FLAG_MORE); 224 qemu_put_be64(f, reallen); 225 for (cx = 0; cx < reallen; cx++) { 226 qemu_put_byte(f, buf[cx]); 227 } 228 if (!sac->get_dirtycount(sas)) { 229 break; 230 } 231 } 232 233 sas->migration_cur_gfn = start_gfn + reallen; 234 g_free(buf); 235 if (final) { 236 qemu_put_be64(f, STATTR_FLAG_DONE); 237 } 238 qemu_put_be64(f, STATTR_FLAG_EOS); 239 240 r = qemu_file_get_error(f); 241 if (r < 0) { 242 return r; 243 } 244 245 return ret; 246 } 247 248 static int cmma_save_iterate(QEMUFile *f, void *opaque) 249 { 250 return cmma_save(f, opaque, 0); 251 } 252 253 static int cmma_save_complete(QEMUFile *f, void *opaque) 254 { 255 return cmma_save(f, opaque, 1); 256 } 257 258 static void cmma_save_cleanup(void *opaque) 259 { 260 S390StAttribState *sas = S390_STATTRIB(opaque); 261 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 262 sac->set_migrationmode(sas, 0); 263 } 264 265 static bool cmma_active(void *opaque) 266 { 267 S390StAttribState *sas = S390_STATTRIB(opaque); 268 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 269 return sac->get_active(sas); 270 } 271 272 /* QEMU object: */ 273 274 static void qemu_s390_stattrib_instance_init(Object *obj) 275 { 276 } 277 278 static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn, 279 uint32_t count, uint8_t *values) 280 { 281 return 0; 282 } 283 static void qemu_s390_synchronize_stub(S390StAttribState *sa) 284 { 285 } 286 static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn, 287 uint32_t count, uint8_t *values) 288 { 289 return 0; 290 } 291 static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa) 292 { 293 return 0; 294 } 295 static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value) 296 { 297 return 0; 298 } 299 300 static int qemu_s390_get_active(S390StAttribState *sa) 301 { 302 return sa->migration_enabled; 303 } 304 305 static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) 306 { 307 S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc); 308 DeviceClass *dc = DEVICE_CLASS(oc); 309 310 sa_cl->synchronize = qemu_s390_synchronize_stub; 311 sa_cl->get_stattr = qemu_s390_get_stattr_stub; 312 sa_cl->set_stattr = qemu_s390_peek_stattr_stub; 313 sa_cl->peek_stattr = qemu_s390_peek_stattr_stub; 314 sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub; 315 sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub; 316 sa_cl->get_active = qemu_s390_get_active; 317 318 /* Reason: Can only be instantiated one time (internally) */ 319 dc->user_creatable = false; 320 } 321 322 static const TypeInfo qemu_s390_stattrib_info = { 323 .name = TYPE_QEMU_S390_STATTRIB, 324 .parent = TYPE_S390_STATTRIB, 325 .instance_init = qemu_s390_stattrib_instance_init, 326 .instance_size = sizeof(QEMUS390StAttribState), 327 .class_init = qemu_s390_stattrib_class_init, 328 .class_size = sizeof(S390StAttribClass), 329 }; 330 331 /* Generic abstract object: */ 332 333 static void s390_stattrib_realize(DeviceState *dev, Error **errp) 334 { 335 bool ambiguous = false; 336 337 object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous); 338 if (ambiguous) { 339 error_setg(errp, "storage_attributes device already exists"); 340 } 341 } 342 343 static void s390_stattrib_class_init(ObjectClass *oc, void *data) 344 { 345 DeviceClass *dc = DEVICE_CLASS(oc); 346 347 dc->hotpluggable = false; 348 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 349 dc->realize = s390_stattrib_realize; 350 } 351 352 static inline bool s390_stattrib_get_migration_enabled(Object *obj, 353 Error **errp) 354 { 355 S390StAttribState *s = S390_STATTRIB(obj); 356 357 return s->migration_enabled; 358 } 359 360 static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value, 361 Error **errp) 362 { 363 S390StAttribState *s = S390_STATTRIB(obj); 364 365 s->migration_enabled = value; 366 } 367 368 static SaveVMHandlers savevm_s390_stattrib_handlers = { 369 .save_setup = cmma_save_setup, 370 .save_live_iterate = cmma_save_iterate, 371 .save_live_complete_precopy = cmma_save_complete, 372 .state_pending_exact = cmma_state_pending, 373 .state_pending_estimate = cmma_state_pending, 374 .save_cleanup = cmma_save_cleanup, 375 .load_state = cmma_load, 376 .is_active = cmma_active, 377 }; 378 379 static void s390_stattrib_instance_init(Object *obj) 380 { 381 S390StAttribState *sas = S390_STATTRIB(obj); 382 383 register_savevm_live(TYPE_S390_STATTRIB, 0, 0, 384 &savevm_s390_stattrib_handlers, sas); 385 386 object_property_add_bool(obj, "migration-enabled", 387 s390_stattrib_get_migration_enabled, 388 s390_stattrib_set_migration_enabled); 389 object_property_set_bool(obj, "migration-enabled", true, NULL); 390 sas->migration_cur_gfn = 0; 391 } 392 393 static const TypeInfo s390_stattrib_info = { 394 .name = TYPE_S390_STATTRIB, 395 .parent = TYPE_DEVICE, 396 .instance_init = s390_stattrib_instance_init, 397 .instance_size = sizeof(S390StAttribState), 398 .class_init = s390_stattrib_class_init, 399 .class_size = sizeof(S390StAttribClass), 400 .abstract = true, 401 }; 402 403 static void s390_stattrib_register_types(void) 404 { 405 type_register_static(&s390_stattrib_info); 406 type_register_static(&qemu_s390_stattrib_info); 407 } 408 409 type_init(s390_stattrib_register_types) 410