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