1 /* 2 * virtio ccw machine 3 * 4 * Copyright 2012 IBM Corp. 5 * Author(s): Cornelia Huck <cornelia.huck@de.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 "qapi/error.h" 14 #include "qemu-common.h" 15 #include "cpu.h" 16 #include "hw/boards.h" 17 #include "exec/address-spaces.h" 18 #include "s390-virtio.h" 19 #include "hw/s390x/sclp.h" 20 #include "hw/s390x/s390_flic.h" 21 #include "hw/s390x/ioinst.h" 22 #include "hw/s390x/css.h" 23 #include "virtio-ccw.h" 24 #include "qemu/config-file.h" 25 #include "s390-pci-bus.h" 26 #include "hw/s390x/storage-keys.h" 27 #include "hw/s390x/storage-attributes.h" 28 #include "hw/compat.h" 29 #include "ipl.h" 30 #include "hw/s390x/s390-virtio-ccw.h" 31 #include "hw/s390x/css-bridge.h" 32 #include "migration/register.h" 33 #include "cpu_models.h" 34 35 static const char *const reset_dev_types[] = { 36 TYPE_VIRTUAL_CSS_BRIDGE, 37 "s390-sclp-event-facility", 38 "s390-flic", 39 "diag288", 40 }; 41 42 void subsystem_reset(void) 43 { 44 DeviceState *dev; 45 int i; 46 47 for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) { 48 dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL)); 49 if (dev) { 50 qdev_reset_all(dev); 51 } 52 } 53 } 54 55 static int virtio_ccw_hcall_notify(const uint64_t *args) 56 { 57 uint64_t subch_id = args[0]; 58 uint64_t queue = args[1]; 59 SubchDev *sch; 60 int cssid, ssid, schid, m; 61 62 if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) { 63 return -EINVAL; 64 } 65 sch = css_find_subch(m, cssid, ssid, schid); 66 if (!sch || !css_subch_visible(sch)) { 67 return -EINVAL; 68 } 69 if (queue >= VIRTIO_QUEUE_MAX) { 70 return -EINVAL; 71 } 72 virtio_queue_notify(virtio_ccw_get_vdev(sch), queue); 73 return 0; 74 75 } 76 77 static int virtio_ccw_hcall_early_printk(const uint64_t *args) 78 { 79 uint64_t mem = args[0]; 80 81 if (mem < ram_size) { 82 /* Early printk */ 83 return 0; 84 } 85 return -EINVAL; 86 } 87 88 static void virtio_ccw_register_hcalls(void) 89 { 90 s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, 91 virtio_ccw_hcall_notify); 92 /* Tolerate early printk. */ 93 s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY, 94 virtio_ccw_hcall_early_printk); 95 } 96 97 void s390_memory_init(ram_addr_t mem_size) 98 { 99 MemoryRegion *sysmem = get_system_memory(); 100 MemoryRegion *ram = g_new(MemoryRegion, 1); 101 102 /* allocate RAM for core */ 103 memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size); 104 memory_region_add_subregion(sysmem, 0, ram); 105 106 /* Initialize storage key device */ 107 s390_skeys_init(); 108 /* Initialize storage attributes device */ 109 s390_stattrib_init(); 110 } 111 112 static SaveVMHandlers savevm_gtod = { 113 .save_state = gtod_save, 114 .load_state = gtod_load, 115 }; 116 117 static void ccw_init(MachineState *machine) 118 { 119 int ret; 120 VirtualCssBus *css_bus; 121 122 s390_sclp_init(); 123 s390_memory_init(machine->ram_size); 124 125 /* init CPUs (incl. CPU model) early so s390_has_feature() works */ 126 s390_init_cpus(machine); 127 128 s390_flic_init(); 129 130 /* get a BUS */ 131 css_bus = virtual_css_bus_init(); 132 s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, 133 machine->initrd_filename, "s390-ccw.img", 134 "s390-netboot.img", true); 135 136 if (s390_has_feat(S390_FEAT_ZPCI)) { 137 DeviceState *dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); 138 object_property_add_child(qdev_get_machine(), 139 TYPE_S390_PCI_HOST_BRIDGE, 140 OBJECT(dev), NULL); 141 qdev_init_nofail(dev); 142 } 143 144 /* register hypercalls */ 145 virtio_ccw_register_hcalls(); 146 147 s390_enable_css_support(s390_cpu_addr2state(0)); 148 /* 149 * Non mcss-e enabled guests only see the devices from the default 150 * css, which is determined by the value of the squash_mcss property. 151 * Note: we must not squash non virtual devices to css 0xFE. 152 */ 153 if (css_bus->squash_mcss) { 154 ret = css_create_css_image(0, true); 155 } else { 156 ret = css_create_css_image(VIRTUAL_CSSID, true); 157 } 158 assert(ret == 0); 159 160 /* Create VirtIO network adapters */ 161 s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); 162 163 /* Register savevm handler for guest TOD clock */ 164 register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL); 165 } 166 167 static void s390_cpu_plug(HotplugHandler *hotplug_dev, 168 DeviceState *dev, Error **errp) 169 { 170 gchar *name; 171 S390CPU *cpu = S390_CPU(dev); 172 CPUState *cs = CPU(dev); 173 174 name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num); 175 object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name, 176 errp); 177 g_free(name); 178 } 179 180 static void s390_machine_device_plug(HotplugHandler *hotplug_dev, 181 DeviceState *dev, Error **errp) 182 { 183 if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 184 s390_cpu_plug(hotplug_dev, dev, errp); 185 } 186 } 187 188 static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, 189 DeviceState *dev) 190 { 191 if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 192 return HOTPLUG_HANDLER(machine); 193 } 194 return NULL; 195 } 196 197 static void s390_hot_add_cpu(const int64_t id, Error **errp) 198 { 199 MachineState *machine = MACHINE(qdev_get_machine()); 200 201 s390x_new_cpu(machine->cpu_model, id, errp); 202 } 203 204 static void ccw_machine_class_init(ObjectClass *oc, void *data) 205 { 206 MachineClass *mc = MACHINE_CLASS(oc); 207 NMIClass *nc = NMI_CLASS(oc); 208 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); 209 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 210 211 s390mc->ri_allowed = true; 212 s390mc->cpu_model_allowed = true; 213 s390mc->css_migration_enabled = true; 214 s390mc->gs_allowed = true; 215 mc->init = ccw_init; 216 mc->reset = s390_machine_reset; 217 mc->hot_add_cpu = s390_hot_add_cpu; 218 mc->block_default_type = IF_VIRTIO; 219 mc->no_cdrom = 1; 220 mc->no_floppy = 1; 221 mc->no_serial = 1; 222 mc->no_parallel = 1; 223 mc->no_sdcard = 1; 224 mc->use_sclp = 1; 225 mc->max_cpus = 248; 226 mc->get_hotplug_handler = s390_get_hotplug_handler; 227 hc->plug = s390_machine_device_plug; 228 nc->nmi_monitor_handler = s390_nmi; 229 } 230 231 static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp) 232 { 233 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 234 235 return ms->aes_key_wrap; 236 } 237 238 static inline void machine_set_aes_key_wrap(Object *obj, bool value, 239 Error **errp) 240 { 241 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 242 243 ms->aes_key_wrap = value; 244 } 245 246 static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp) 247 { 248 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 249 250 return ms->dea_key_wrap; 251 } 252 253 static inline void machine_set_dea_key_wrap(Object *obj, bool value, 254 Error **errp) 255 { 256 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 257 258 ms->dea_key_wrap = value; 259 } 260 261 static S390CcwMachineClass *current_mc; 262 263 static S390CcwMachineClass *get_machine_class(void) 264 { 265 if (unlikely(!current_mc)) { 266 /* 267 * No s390 ccw machine was instantiated, we are likely to 268 * be called for the 'none' machine. The properties will 269 * have their after-initialization values. 270 */ 271 current_mc = S390_MACHINE_CLASS( 272 object_class_by_name(TYPE_S390_CCW_MACHINE)); 273 } 274 return current_mc; 275 } 276 277 bool ri_allowed(void) 278 { 279 /* for "none" machine this results in true */ 280 return get_machine_class()->ri_allowed; 281 } 282 283 bool cpu_model_allowed(void) 284 { 285 /* for "none" machine this results in true */ 286 return get_machine_class()->cpu_model_allowed; 287 } 288 289 bool gs_allowed(void) 290 { 291 /* for "none" machine this results in true */ 292 return get_machine_class()->gs_allowed; 293 } 294 295 static char *machine_get_loadparm(Object *obj, Error **errp) 296 { 297 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 298 299 return g_memdup(ms->loadparm, sizeof(ms->loadparm)); 300 } 301 302 static void machine_set_loadparm(Object *obj, const char *val, Error **errp) 303 { 304 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 305 int i; 306 307 for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) { 308 uint8_t c = qemu_toupper(val[i]); /* mimic HMC */ 309 310 if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') || 311 (c == ' ')) { 312 ms->loadparm[i] = c; 313 } else { 314 error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)", 315 c, c); 316 return; 317 } 318 } 319 320 for (; i < sizeof(ms->loadparm); i++) { 321 ms->loadparm[i] = ' '; /* pad right with spaces */ 322 } 323 } 324 static inline bool machine_get_squash_mcss(Object *obj, Error **errp) 325 { 326 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 327 328 return ms->s390_squash_mcss; 329 } 330 331 static inline void machine_set_squash_mcss(Object *obj, bool value, 332 Error **errp) 333 { 334 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 335 336 ms->s390_squash_mcss = value; 337 } 338 339 static inline void s390_machine_initfn(Object *obj) 340 { 341 object_property_add_bool(obj, "aes-key-wrap", 342 machine_get_aes_key_wrap, 343 machine_set_aes_key_wrap, NULL); 344 object_property_set_description(obj, "aes-key-wrap", 345 "enable/disable AES key wrapping using the CPACF wrapping key", 346 NULL); 347 object_property_set_bool(obj, true, "aes-key-wrap", NULL); 348 349 object_property_add_bool(obj, "dea-key-wrap", 350 machine_get_dea_key_wrap, 351 machine_set_dea_key_wrap, NULL); 352 object_property_set_description(obj, "dea-key-wrap", 353 "enable/disable DEA key wrapping using the CPACF wrapping key", 354 NULL); 355 object_property_set_bool(obj, true, "dea-key-wrap", NULL); 356 object_property_add_str(obj, "loadparm", 357 machine_get_loadparm, machine_set_loadparm, NULL); 358 object_property_set_description(obj, "loadparm", 359 "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted" 360 " to upper case) to pass to machine loader, boot manager," 361 " and guest kernel", 362 NULL); 363 object_property_add_bool(obj, "s390-squash-mcss", 364 machine_get_squash_mcss, 365 machine_set_squash_mcss, NULL); 366 object_property_set_description(obj, "s390-squash-mcss", 367 "enable/disable squashing subchannels into the default css", 368 NULL); 369 object_property_set_bool(obj, false, "s390-squash-mcss", NULL); 370 } 371 372 static const TypeInfo ccw_machine_info = { 373 .name = TYPE_S390_CCW_MACHINE, 374 .parent = TYPE_MACHINE, 375 .abstract = true, 376 .instance_size = sizeof(S390CcwMachineState), 377 .instance_init = s390_machine_initfn, 378 .class_size = sizeof(S390CcwMachineClass), 379 .class_init = ccw_machine_class_init, 380 .interfaces = (InterfaceInfo[]) { 381 { TYPE_NMI }, 382 { TYPE_HOTPLUG_HANDLER}, 383 { } 384 }, 385 }; 386 387 bool css_migration_enabled(void) 388 { 389 return get_machine_class()->css_migration_enabled; 390 } 391 392 #define DEFINE_CCW_MACHINE(suffix, verstr, latest) \ 393 static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \ 394 void *data) \ 395 { \ 396 MachineClass *mc = MACHINE_CLASS(oc); \ 397 ccw_machine_##suffix##_class_options(mc); \ 398 mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ 399 if (latest) { \ 400 mc->alias = "s390-ccw-virtio"; \ 401 mc->is_default = 1; \ 402 } \ 403 } \ 404 static void ccw_machine_##suffix##_instance_init(Object *obj) \ 405 { \ 406 MachineState *machine = MACHINE(obj); \ 407 current_mc = S390_MACHINE_CLASS(MACHINE_GET_CLASS(machine)); \ 408 ccw_machine_##suffix##_instance_options(machine); \ 409 } \ 410 static const TypeInfo ccw_machine_##suffix##_info = { \ 411 .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \ 412 .parent = TYPE_S390_CCW_MACHINE, \ 413 .class_init = ccw_machine_##suffix##_class_init, \ 414 .instance_init = ccw_machine_##suffix##_instance_init, \ 415 }; \ 416 static void ccw_machine_register_##suffix(void) \ 417 { \ 418 type_register_static(&ccw_machine_##suffix##_info); \ 419 } \ 420 type_init(ccw_machine_register_##suffix) 421 422 #define CCW_COMPAT_2_10 \ 423 HW_COMPAT_2_10 424 425 #define CCW_COMPAT_2_9 \ 426 HW_COMPAT_2_9 \ 427 {\ 428 .driver = TYPE_S390_STATTRIB,\ 429 .property = "migration-enabled",\ 430 .value = "off",\ 431 }, 432 433 #define CCW_COMPAT_2_8 \ 434 HW_COMPAT_2_8 \ 435 {\ 436 .driver = TYPE_S390_FLIC_COMMON,\ 437 .property = "adapter_routes_max_batch",\ 438 .value = "64",\ 439 }, 440 441 #define CCW_COMPAT_2_7 \ 442 HW_COMPAT_2_7 443 444 #define CCW_COMPAT_2_6 \ 445 HW_COMPAT_2_6 \ 446 {\ 447 .driver = TYPE_S390_IPL,\ 448 .property = "iplbext_migration",\ 449 .value = "off",\ 450 }, {\ 451 .driver = TYPE_VIRTUAL_CSS_BRIDGE,\ 452 .property = "css_dev_path",\ 453 .value = "off",\ 454 }, 455 456 #define CCW_COMPAT_2_5 \ 457 HW_COMPAT_2_5 458 459 #define CCW_COMPAT_2_4 \ 460 HW_COMPAT_2_4 \ 461 {\ 462 .driver = TYPE_S390_SKEYS,\ 463 .property = "migration-enabled",\ 464 .value = "off",\ 465 },{\ 466 .driver = "virtio-blk-ccw",\ 467 .property = "max_revision",\ 468 .value = "0",\ 469 },{\ 470 .driver = "virtio-balloon-ccw",\ 471 .property = "max_revision",\ 472 .value = "0",\ 473 },{\ 474 .driver = "virtio-serial-ccw",\ 475 .property = "max_revision",\ 476 .value = "0",\ 477 },{\ 478 .driver = "virtio-9p-ccw",\ 479 .property = "max_revision",\ 480 .value = "0",\ 481 },{\ 482 .driver = "virtio-rng-ccw",\ 483 .property = "max_revision",\ 484 .value = "0",\ 485 },{\ 486 .driver = "virtio-net-ccw",\ 487 .property = "max_revision",\ 488 .value = "0",\ 489 },{\ 490 .driver = "virtio-scsi-ccw",\ 491 .property = "max_revision",\ 492 .value = "0",\ 493 },{\ 494 .driver = "vhost-scsi-ccw",\ 495 .property = "max_revision",\ 496 .value = "0",\ 497 }, 498 499 static void ccw_machine_2_11_instance_options(MachineState *machine) 500 { 501 } 502 503 static void ccw_machine_2_11_class_options(MachineClass *mc) 504 { 505 } 506 DEFINE_CCW_MACHINE(2_11, "2.11", true); 507 508 static void ccw_machine_2_10_instance_options(MachineState *machine) 509 { 510 ccw_machine_2_11_instance_options(machine); 511 if (css_migration_enabled()) { 512 css_register_vmstate(); 513 } 514 } 515 516 static void ccw_machine_2_10_class_options(MachineClass *mc) 517 { 518 ccw_machine_2_11_class_options(mc); 519 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_10); 520 } 521 DEFINE_CCW_MACHINE(2_10, "2.10", false); 522 523 static void ccw_machine_2_9_instance_options(MachineState *machine) 524 { 525 ccw_machine_2_10_instance_options(machine); 526 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP); 527 s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2); 528 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI); 529 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION); 530 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION); 531 } 532 533 static void ccw_machine_2_9_class_options(MachineClass *mc) 534 { 535 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 536 537 s390mc->gs_allowed = false; 538 ccw_machine_2_10_class_options(mc); 539 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9); 540 s390mc->css_migration_enabled = false; 541 } 542 DEFINE_CCW_MACHINE(2_9, "2.9", false); 543 544 static void ccw_machine_2_8_instance_options(MachineState *machine) 545 { 546 ccw_machine_2_9_instance_options(machine); 547 } 548 549 static void ccw_machine_2_8_class_options(MachineClass *mc) 550 { 551 ccw_machine_2_9_class_options(mc); 552 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_8); 553 } 554 DEFINE_CCW_MACHINE(2_8, "2.8", false); 555 556 static void ccw_machine_2_7_instance_options(MachineState *machine) 557 { 558 ccw_machine_2_8_instance_options(machine); 559 } 560 561 static void ccw_machine_2_7_class_options(MachineClass *mc) 562 { 563 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 564 565 s390mc->cpu_model_allowed = false; 566 ccw_machine_2_8_class_options(mc); 567 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7); 568 } 569 DEFINE_CCW_MACHINE(2_7, "2.7", false); 570 571 static void ccw_machine_2_6_instance_options(MachineState *machine) 572 { 573 ccw_machine_2_7_instance_options(machine); 574 } 575 576 static void ccw_machine_2_6_class_options(MachineClass *mc) 577 { 578 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 579 580 s390mc->ri_allowed = false; 581 ccw_machine_2_7_class_options(mc); 582 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6); 583 } 584 DEFINE_CCW_MACHINE(2_6, "2.6", false); 585 586 static void ccw_machine_2_5_instance_options(MachineState *machine) 587 { 588 ccw_machine_2_6_instance_options(machine); 589 } 590 591 static void ccw_machine_2_5_class_options(MachineClass *mc) 592 { 593 ccw_machine_2_6_class_options(mc); 594 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5); 595 } 596 DEFINE_CCW_MACHINE(2_5, "2.5", false); 597 598 static void ccw_machine_2_4_instance_options(MachineState *machine) 599 { 600 ccw_machine_2_5_instance_options(machine); 601 } 602 603 static void ccw_machine_2_4_class_options(MachineClass *mc) 604 { 605 ccw_machine_2_5_class_options(mc); 606 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4); 607 } 608 DEFINE_CCW_MACHINE(2_4, "2.4", false); 609 610 static void ccw_machine_register_types(void) 611 { 612 type_register_static(&ccw_machine_info); 613 } 614 615 type_init(ccw_machine_register_types) 616