s390-skeys.c (15139B)
1/* 2 * s390 storage key device 3 * 4 * Copyright 2015 IBM Corp. 5 * Author(s): Jason J. Herne <jjherne@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 "hw/s390x/storage-keys.h" 16#include "qapi/error.h" 17#include "qapi/qapi-commands-misc-target.h" 18#include "qapi/qmp/qdict.h" 19#include "qemu/error-report.h" 20#include "sysemu/memory_mapping.h" 21#include "exec/address-spaces.h" 22#include "sysemu/kvm.h" 23#include "migration/qemu-file-types.h" 24#include "migration/register.h" 25 26#define S390_SKEYS_BUFFER_SIZE (128 * KiB) /* Room for 128k storage keys */ 27#define S390_SKEYS_SAVE_FLAG_EOS 0x01 28#define S390_SKEYS_SAVE_FLAG_SKEYS 0x02 29#define S390_SKEYS_SAVE_FLAG_ERROR 0x04 30 31S390SKeysState *s390_get_skeys_device(void) 32{ 33 S390SKeysState *ss; 34 35 ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL)); 36 assert(ss); 37 return ss; 38} 39 40void s390_skeys_init(void) 41{ 42 Object *obj; 43 44 if (kvm_enabled()) { 45 obj = object_new(TYPE_KVM_S390_SKEYS); 46 } else { 47 obj = object_new(TYPE_QEMU_S390_SKEYS); 48 } 49 object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS, 50 obj); 51 object_unref(obj); 52 53 qdev_realize(DEVICE(obj), NULL, &error_fatal); 54} 55 56static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn, 57 uint64_t count, Error **errp) 58{ 59 uint64_t curpage = startgfn; 60 uint64_t maxpage = curpage + count - 1; 61 62 for (; curpage <= maxpage; curpage++) { 63 uint8_t acc = (*keys & 0xF0) >> 4; 64 int fp = (*keys & 0x08); 65 int ref = (*keys & 0x04); 66 int ch = (*keys & 0x02); 67 int res = (*keys & 0x01); 68 69 fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d," 70 " ch=%d, reserved=%d\n", 71 curpage, *keys, acc, fp, ref, ch, res); 72 keys++; 73 } 74} 75 76void hmp_info_skeys(Monitor *mon, const QDict *qdict) 77{ 78 S390SKeysState *ss = s390_get_skeys_device(); 79 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); 80 uint64_t addr = qdict_get_int(qdict, "addr"); 81 uint8_t key; 82 int r; 83 84 /* Quick check to see if guest is using storage keys*/ 85 if (!skeyclass->skeys_are_enabled(ss)) { 86 monitor_printf(mon, "Error: This guest is not using storage keys\n"); 87 return; 88 } 89 90 if (!address_space_access_valid(&address_space_memory, 91 addr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE, 92 false, MEMTXATTRS_UNSPECIFIED)) { 93 monitor_printf(mon, "Error: The given address is not valid\n"); 94 return; 95 } 96 97 r = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); 98 if (r < 0) { 99 monitor_printf(mon, "Error: %s\n", strerror(-r)); 100 return; 101 } 102 103 monitor_printf(mon, " key: 0x%X\n", key); 104} 105 106void hmp_dump_skeys(Monitor *mon, const QDict *qdict) 107{ 108 const char *filename = qdict_get_str(qdict, "filename"); 109 Error *err = NULL; 110 111 qmp_dump_skeys(filename, &err); 112 if (err) { 113 error_report_err(err); 114 } 115} 116 117void qmp_dump_skeys(const char *filename, Error **errp) 118{ 119 S390SKeysState *ss = s390_get_skeys_device(); 120 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); 121 GuestPhysBlockList guest_phys_blocks; 122 GuestPhysBlock *block; 123 uint64_t pages, gfn; 124 Error *lerr = NULL; 125 uint8_t *buf; 126 int ret; 127 int fd; 128 FILE *f; 129 130 /* Quick check to see if guest is using storage keys*/ 131 if (!skeyclass->skeys_are_enabled(ss)) { 132 error_setg(errp, "This guest is not using storage keys - " 133 "nothing to dump"); 134 return; 135 } 136 137 fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); 138 if (fd < 0) { 139 error_setg_file_open(errp, errno, filename); 140 return; 141 } 142 f = fdopen(fd, "wb"); 143 if (!f) { 144 close(fd); 145 error_setg_file_open(errp, errno, filename); 146 return; 147 } 148 149 buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); 150 if (!buf) { 151 error_setg(errp, "Could not allocate memory"); 152 goto out; 153 } 154 155 assert(qemu_mutex_iothread_locked()); 156 guest_phys_blocks_init(&guest_phys_blocks); 157 guest_phys_blocks_append(&guest_phys_blocks); 158 159 QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) { 160 assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE)); 161 assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE)); 162 163 gfn = block->target_start / TARGET_PAGE_SIZE; 164 pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE; 165 166 while (pages) { 167 const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE); 168 169 ret = skeyclass->get_skeys(ss, gfn, cur_pages, buf); 170 if (ret < 0) { 171 error_setg_errno(errp, -ret, "get_keys error"); 172 goto out_free; 173 } 174 175 /* write keys to stream */ 176 write_keys(f, buf, gfn, cur_pages, &lerr); 177 if (lerr) { 178 goto out_free; 179 } 180 181 gfn += cur_pages; 182 pages -= cur_pages; 183 } 184 } 185 186out_free: 187 guest_phys_blocks_free(&guest_phys_blocks); 188 error_propagate(errp, lerr); 189 g_free(buf); 190out: 191 fclose(f); 192} 193 194static bool qemu_s390_skeys_are_enabled(S390SKeysState *ss) 195{ 196 QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss); 197 198 /* Lockless check is sufficient. */ 199 return !!skeys->keydata; 200} 201 202static bool qemu_s390_enable_skeys(S390SKeysState *ss) 203{ 204 QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss); 205 static gsize initialized; 206 207 if (likely(skeys->keydata)) { 208 return true; 209 } 210 211 /* 212 * TODO: Modern Linux doesn't use storage keys unless running KVM guests 213 * that use storage keys. Therefore, we keep it simple for now. 214 * 215 * 1) We should initialize to "referenced+changed" for an initial 216 * over-indication. Let's avoid touching megabytes of data for now and 217 * assume that any sane user will issue a storage key instruction before 218 * actually relying on this data. 219 * 2) Relying on ram_size and allocating a big array is ugly. We should 220 * allocate and manage storage key data per RAMBlock or optimally using 221 * some sparse data structure. 222 * 3) We only ever have a single S390SKeysState, so relying on 223 * g_once_init_enter() is good enough. 224 */ 225 if (g_once_init_enter(&initialized)) { 226 MachineState *machine = MACHINE(qdev_get_machine()); 227 228 skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE; 229 skeys->keydata = g_malloc0(skeys->key_count); 230 g_once_init_leave(&initialized, 1); 231 } 232 return false; 233} 234 235static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, 236 uint64_t count, uint8_t *keys) 237{ 238 QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss); 239 int i; 240 241 /* Check for uint64 overflow and access beyond end of key data */ 242 if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count || 243 start_gfn + count < count)) { 244 error_report("Error: Setting storage keys for pages with unallocated " 245 "storage key memory: gfn=%" PRIx64 " count=%" PRId64, 246 start_gfn, count); 247 return -EINVAL; 248 } 249 250 for (i = 0; i < count; i++) { 251 skeydev->keydata[start_gfn + i] = keys[i]; 252 } 253 return 0; 254} 255 256static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, 257 uint64_t count, uint8_t *keys) 258{ 259 QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss); 260 int i; 261 262 /* Check for uint64 overflow and access beyond end of key data */ 263 if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count || 264 start_gfn + count < count)) { 265 error_report("Error: Getting storage keys for pages with unallocated " 266 "storage key memory: gfn=%" PRIx64 " count=%" PRId64, 267 start_gfn, count); 268 return -EINVAL; 269 } 270 271 for (i = 0; i < count; i++) { 272 keys[i] = skeydev->keydata[start_gfn + i]; 273 } 274 return 0; 275} 276 277static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) 278{ 279 S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); 280 DeviceClass *dc = DEVICE_CLASS(oc); 281 282 skeyclass->skeys_are_enabled = qemu_s390_skeys_are_enabled; 283 skeyclass->enable_skeys = qemu_s390_enable_skeys; 284 skeyclass->get_skeys = qemu_s390_skeys_get; 285 skeyclass->set_skeys = qemu_s390_skeys_set; 286 287 /* Reason: Internal device (only one skeys device for the whole memory) */ 288 dc->user_creatable = false; 289} 290 291static const TypeInfo qemu_s390_skeys_info = { 292 .name = TYPE_QEMU_S390_SKEYS, 293 .parent = TYPE_S390_SKEYS, 294 .instance_size = sizeof(QEMUS390SKeysState), 295 .class_init = qemu_s390_skeys_class_init, 296 .class_size = sizeof(S390SKeysClass), 297}; 298 299static void s390_storage_keys_save(QEMUFile *f, void *opaque) 300{ 301 S390SKeysState *ss = S390_SKEYS(opaque); 302 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); 303 GuestPhysBlockList guest_phys_blocks; 304 GuestPhysBlock *block; 305 uint64_t pages, gfn; 306 int error = 0; 307 uint8_t *buf; 308 309 if (!skeyclass->skeys_are_enabled(ss)) { 310 goto end_stream; 311 } 312 313 buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); 314 if (!buf) { 315 error_report("storage key save could not allocate memory"); 316 goto end_stream; 317 } 318 319 guest_phys_blocks_init(&guest_phys_blocks); 320 guest_phys_blocks_append(&guest_phys_blocks); 321 322 /* Send each contiguous physical memory range separately. */ 323 QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) { 324 assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE)); 325 assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE)); 326 327 gfn = block->target_start / TARGET_PAGE_SIZE; 328 pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE; 329 qemu_put_be64(f, block->target_start | S390_SKEYS_SAVE_FLAG_SKEYS); 330 qemu_put_be64(f, pages); 331 332 while (pages) { 333 const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE); 334 335 if (!error) { 336 error = skeyclass->get_skeys(ss, gfn, cur_pages, buf); 337 if (error) { 338 /* 339 * Create a valid stream with all 0x00 and indicate 340 * S390_SKEYS_SAVE_FLAG_ERROR to the destination. 341 */ 342 error_report("S390_GET_KEYS error %d", error); 343 memset(buf, 0, S390_SKEYS_BUFFER_SIZE); 344 } 345 } 346 347 qemu_put_buffer(f, buf, cur_pages); 348 gfn += cur_pages; 349 pages -= cur_pages; 350 } 351 352 if (error) { 353 break; 354 } 355 } 356 357 guest_phys_blocks_free(&guest_phys_blocks); 358 g_free(buf); 359end_stream: 360 if (error) { 361 qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_ERROR); 362 } else { 363 qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_EOS); 364 } 365} 366 367static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id) 368{ 369 S390SKeysState *ss = S390_SKEYS(opaque); 370 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); 371 int ret = 0; 372 373 /* 374 * Make sure to lazy-enable if required to be done explicitly. No need to 375 * flush any TLB as the VM is not running yet. 376 */ 377 if (skeyclass->enable_skeys) { 378 skeyclass->enable_skeys(ss); 379 } 380 381 while (!ret) { 382 ram_addr_t addr; 383 int flags; 384 385 addr = qemu_get_be64(f); 386 flags = addr & ~TARGET_PAGE_MASK; 387 addr &= TARGET_PAGE_MASK; 388 389 switch (flags) { 390 case S390_SKEYS_SAVE_FLAG_SKEYS: { 391 const uint64_t total_count = qemu_get_be64(f); 392 uint64_t handled_count = 0, cur_count; 393 uint64_t cur_gfn = addr / TARGET_PAGE_SIZE; 394 uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); 395 396 if (!buf) { 397 error_report("storage key load could not allocate memory"); 398 ret = -ENOMEM; 399 break; 400 } 401 402 while (handled_count < total_count) { 403 cur_count = MIN(total_count - handled_count, 404 S390_SKEYS_BUFFER_SIZE); 405 qemu_get_buffer(f, buf, cur_count); 406 407 ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf); 408 if (ret < 0) { 409 error_report("S390_SET_KEYS error %d", ret); 410 break; 411 } 412 handled_count += cur_count; 413 cur_gfn += cur_count; 414 } 415 g_free(buf); 416 break; 417 } 418 case S390_SKEYS_SAVE_FLAG_ERROR: { 419 error_report("Storage key data is incomplete"); 420 ret = -EINVAL; 421 break; 422 } 423 case S390_SKEYS_SAVE_FLAG_EOS: 424 /* normal exit */ 425 return 0; 426 default: 427 error_report("Unexpected storage key flag data: %#x", flags); 428 ret = -EINVAL; 429 } 430 } 431 432 return ret; 433} 434 435static inline bool s390_skeys_get_migration_enabled(Object *obj, Error **errp) 436{ 437 S390SKeysState *ss = S390_SKEYS(obj); 438 439 return ss->migration_enabled; 440} 441 442static SaveVMHandlers savevm_s390_storage_keys = { 443 .save_state = s390_storage_keys_save, 444 .load_state = s390_storage_keys_load, 445}; 446 447static inline void s390_skeys_set_migration_enabled(Object *obj, bool value, 448 Error **errp) 449{ 450 S390SKeysState *ss = S390_SKEYS(obj); 451 452 /* Prevent double registration of savevm handler */ 453 if (ss->migration_enabled == value) { 454 return; 455 } 456 457 ss->migration_enabled = value; 458 459 if (ss->migration_enabled) { 460 register_savevm_live(TYPE_S390_SKEYS, 0, 1, 461 &savevm_s390_storage_keys, ss); 462 } else { 463 unregister_savevm(VMSTATE_IF(ss), TYPE_S390_SKEYS, ss); 464 } 465} 466 467static void s390_skeys_instance_init(Object *obj) 468{ 469 object_property_add_bool(obj, "migration-enabled", 470 s390_skeys_get_migration_enabled, 471 s390_skeys_set_migration_enabled); 472 object_property_set_bool(obj, "migration-enabled", true, NULL); 473} 474 475static void s390_skeys_class_init(ObjectClass *oc, void *data) 476{ 477 DeviceClass *dc = DEVICE_CLASS(oc); 478 479 dc->hotpluggable = false; 480 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 481} 482 483static const TypeInfo s390_skeys_info = { 484 .name = TYPE_S390_SKEYS, 485 .parent = TYPE_DEVICE, 486 .instance_init = s390_skeys_instance_init, 487 .instance_size = sizeof(S390SKeysState), 488 .class_init = s390_skeys_class_init, 489 .class_size = sizeof(S390SKeysClass), 490 .abstract = true, 491}; 492 493static void qemu_s390_skeys_register_types(void) 494{ 495 type_register_static(&s390_skeys_info); 496 type_register_static(&qemu_s390_skeys_info); 497} 498 499type_init(qemu_s390_skeys_register_types)