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/qdev-properties.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); 51 object_unref(obj); 52 53 qdev_realize(DEVICE(obj), NULL, &error_fatal); 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 Error *local_err = NULL; 64 int r; 65 66 r = sac->set_migrationmode(sas, what, &local_err); 67 if (r < 0) { 68 monitor_printf(mon, "Error: %s", error_get_pretty(local_err)); 69 error_free(local_err); 70 } 71 } 72 73 void hmp_info_cmma(Monitor *mon, const QDict *qdict) 74 { 75 S390StAttribState *sas = s390_get_stattrib_device(); 76 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 77 uint64_t addr = qdict_get_int(qdict, "addr"); 78 uint64_t buflen = qdict_get_try_int(qdict, "count", 8); 79 uint8_t *vals; 80 int cx, len; 81 82 vals = g_try_malloc(buflen); 83 if (!vals) { 84 monitor_printf(mon, "Error: %s\n", strerror(errno)); 85 return; 86 } 87 88 len = sac->peek_stattr(sas, addr / TARGET_PAGE_SIZE, buflen, vals); 89 if (len < 0) { 90 monitor_printf(mon, "Error: %s", strerror(-len)); 91 goto out; 92 } 93 94 monitor_printf(mon, " CMMA attributes, " 95 "pages %" PRIu64 "+%d (0x%" PRIx64 "):\n", 96 addr / TARGET_PAGE_SIZE, len, addr & ~TARGET_PAGE_MASK); 97 for (cx = 0; cx < len; cx++) { 98 if (cx % 8 == 7) { 99 monitor_printf(mon, "%02x\n", vals[cx]); 100 } else { 101 monitor_printf(mon, "%02x", vals[cx]); 102 } 103 } 104 monitor_printf(mon, "\n"); 105 106 out: 107 g_free(vals); 108 } 109 110 /* Migration support: */ 111 112 static int cmma_load(QEMUFile *f, void *opaque, int version_id) 113 { 114 S390StAttribState *sas = S390_STATTRIB(opaque); 115 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 116 uint64_t count, cur_gfn; 117 int flags, ret = 0; 118 ram_addr_t addr; 119 uint8_t *buf; 120 121 while (!ret) { 122 addr = qemu_get_be64(f); 123 flags = addr & ~TARGET_PAGE_MASK; 124 addr &= TARGET_PAGE_MASK; 125 126 switch (flags) { 127 case STATTR_FLAG_MORE: { 128 cur_gfn = addr / TARGET_PAGE_SIZE; 129 count = qemu_get_be64(f); 130 buf = g_try_malloc(count); 131 if (!buf) { 132 error_report("cmma_load could not allocate memory"); 133 ret = -ENOMEM; 134 break; 135 } 136 137 qemu_get_buffer(f, buf, count); 138 ret = sac->set_stattr(sas, cur_gfn, count, buf); 139 if (ret < 0) { 140 error_report("Error %d while setting storage attributes", ret); 141 } 142 g_free(buf); 143 break; 144 } 145 case STATTR_FLAG_ERROR: { 146 error_report("Storage attributes data is incomplete"); 147 ret = -EINVAL; 148 break; 149 } 150 case STATTR_FLAG_DONE: 151 /* This is after the last pre-copied value has been sent, nothing 152 * more will be sent after this. Pre-copy has finished, and we 153 * are done flushing all the remaining values. Now the target 154 * system is about to take over. We synchronize the buffer to 155 * apply the actual correct values where needed. 156 */ 157 sac->synchronize(sas); 158 break; 159 case STATTR_FLAG_EOS: 160 /* Normal exit */ 161 return 0; 162 default: 163 error_report("Unexpected storage attribute flag data: %#x", flags); 164 ret = -EINVAL; 165 } 166 } 167 168 return ret; 169 } 170 171 static int cmma_save_setup(QEMUFile *f, void *opaque, Error **errp) 172 { 173 S390StAttribState *sas = S390_STATTRIB(opaque); 174 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 175 int res; 176 /* 177 * Signal that we want to start a migration, thus needing PGSTE dirty 178 * tracking. 179 */ 180 res = sac->set_migrationmode(sas, true, errp); 181 if (res) { 182 return res; 183 } 184 qemu_put_be64(f, STATTR_FLAG_EOS); 185 return 0; 186 } 187 188 static void cmma_state_pending(void *opaque, uint64_t *must_precopy, 189 uint64_t *can_postcopy) 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 *must_precopy += 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 : migration_rate_exceeded(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, false, NULL); 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 Error **errp) 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 SaveVMHandlers savevm_s390_stattrib_handlers = { 338 .save_setup = cmma_save_setup, 339 .save_live_iterate = cmma_save_iterate, 340 .save_live_complete_precopy = cmma_save_complete, 341 .state_pending_exact = cmma_state_pending, 342 .state_pending_estimate = cmma_state_pending, 343 .save_cleanup = cmma_save_cleanup, 344 .load_state = cmma_load, 345 .is_active = cmma_active, 346 }; 347 348 static void s390_stattrib_realize(DeviceState *dev, Error **errp) 349 { 350 bool ambiguous = false; 351 352 object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous); 353 if (ambiguous) { 354 error_setg(errp, "storage_attributes device already exists"); 355 return; 356 } 357 358 register_savevm_live(TYPE_S390_STATTRIB, 0, 0, 359 &savevm_s390_stattrib_handlers, dev); 360 } 361 362 static Property s390_stattrib_props[] = { 363 DEFINE_PROP_BOOL("migration-enabled", S390StAttribState, migration_enabled, true), 364 DEFINE_PROP_END_OF_LIST(), 365 }; 366 367 static void s390_stattrib_class_init(ObjectClass *oc, void *data) 368 { 369 DeviceClass *dc = DEVICE_CLASS(oc); 370 371 dc->hotpluggable = false; 372 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 373 dc->realize = s390_stattrib_realize; 374 device_class_set_props(dc, s390_stattrib_props); 375 } 376 377 static void s390_stattrib_instance_init(Object *obj) 378 { 379 S390StAttribState *sas = S390_STATTRIB(obj); 380 381 sas->migration_cur_gfn = 0; 382 } 383 384 static const TypeInfo s390_stattrib_info = { 385 .name = TYPE_S390_STATTRIB, 386 .parent = TYPE_DEVICE, 387 .instance_init = s390_stattrib_instance_init, 388 .instance_size = sizeof(S390StAttribState), 389 .class_init = s390_stattrib_class_init, 390 .class_size = sizeof(S390StAttribClass), 391 .abstract = true, 392 }; 393 394 static void s390_stattrib_register_types(void) 395 { 396 type_register_static(&s390_stattrib_info); 397 type_register_static(&qemu_s390_stattrib_info); 398 } 399 400 type_init(s390_stattrib_register_types) 401