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 32 static 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 41 void 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 59 void 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 72 void 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 105 out: 106 g_free(vals); 107 } 108 109 /* Migration support: */ 110 111 static 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 170 static 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 187 static 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 201 static 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 252 static int cmma_save_iterate(QEMUFile *f, void *opaque) 253 { 254 return cmma_save(f, opaque, 0); 255 } 256 257 static int cmma_save_complete(QEMUFile *f, void *opaque) 258 { 259 return cmma_save(f, opaque, 1); 260 } 261 262 static 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 269 static 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 278 static void qemu_s390_stattrib_instance_init(Object *obj) 279 { 280 } 281 282 static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn, 283 uint32_t count, uint8_t *values) 284 { 285 return 0; 286 } 287 static void qemu_s390_synchronize_stub(S390StAttribState *sa) 288 { 289 } 290 static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn, 291 uint32_t count, uint8_t *values) 292 { 293 return 0; 294 } 295 static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa) 296 { 297 return 0; 298 } 299 static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value) 300 { 301 return 0; 302 } 303 304 static int qemu_s390_get_active(S390StAttribState *sa) 305 { 306 return sa->migration_enabled; 307 } 308 309 static 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 326 static 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 337 static 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 347 static 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 356 static 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 363 static 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 371 static 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 381 static 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 395 static 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 405 static void s390_stattrib_register_types(void) 406 { 407 type_register_static(&s390_stattrib_info); 408 type_register_static(&qemu_s390_stattrib_info); 409 } 410 411 type_init(s390_stattrib_register_types) 412