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 "hw/boards.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 #define CMMA_BLOCK_SIZE (1 << 10) 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, NULL); 50 object_unref(obj); 51 52 qdev_init_nofail(DEVICE(obj)); 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 = 1 << 19; /* 512kB cover 2GB of guest memory */ 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, Error **e) 355 { 356 S390StAttribState *s = S390_STATTRIB(obj); 357 358 return s->migration_enabled; 359 } 360 361 static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value, 362 Error **errp) 363 { 364 S390StAttribState *s = S390_STATTRIB(obj); 365 366 s->migration_enabled = value; 367 } 368 369 static SaveVMHandlers savevm_s390_stattrib_handlers = { 370 .save_setup = cmma_save_setup, 371 .save_live_iterate = cmma_save_iterate, 372 .save_live_complete_precopy = cmma_save_complete, 373 .save_live_pending = cmma_save_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(NULL, 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, NULL); 389 object_property_set_bool(obj, true, "migration-enabled", 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