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 DeviceState *dev; 122 123 s390_sclp_init(); 124 s390_memory_init(machine->ram_size); 125 126 /* init CPUs */ 127 s390_init_cpus(machine); 128 129 s390_flic_init(); 130 131 /* get a BUS */ 132 css_bus = virtual_css_bus_init(); 133 s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, 134 machine->initrd_filename, "s390-ccw.img", 135 "s390-netboot.img", true); 136 137 dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); 138 object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, 139 OBJECT(dev), NULL); 140 qdev_init_nofail(dev); 141 142 /* register hypercalls */ 143 virtio_ccw_register_hcalls(); 144 145 if (kvm_enabled()) { 146 kvm_s390_enable_css_support(s390_cpu_addr2state(0)); 147 } 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, kvm_state); 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 if (!kvm_enabled()) { 280 return false; 281 } 282 /* for "none" machine this results in true */ 283 return get_machine_class()->ri_allowed; 284 } 285 286 bool cpu_model_allowed(void) 287 { 288 /* for "none" machine this results in true */ 289 return get_machine_class()->cpu_model_allowed; 290 } 291 292 bool gs_allowed(void) 293 { 294 if (kvm_enabled()) { 295 MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); 296 if (object_class_dynamic_cast(OBJECT_CLASS(mc), 297 TYPE_S390_CCW_MACHINE)) { 298 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 299 300 return s390mc->gs_allowed; 301 } 302 /* Make sure the "none" machine can have gs */ 303 return true; 304 } 305 return false; 306 } 307 308 static char *machine_get_loadparm(Object *obj, Error **errp) 309 { 310 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 311 312 return g_memdup(ms->loadparm, sizeof(ms->loadparm)); 313 } 314 315 static void machine_set_loadparm(Object *obj, const char *val, Error **errp) 316 { 317 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 318 int i; 319 320 for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) { 321 uint8_t c = toupper(val[i]); /* mimic HMC */ 322 323 if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') || 324 (c == ' ')) { 325 ms->loadparm[i] = c; 326 } else { 327 error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)", 328 c, c); 329 return; 330 } 331 } 332 333 for (; i < sizeof(ms->loadparm); i++) { 334 ms->loadparm[i] = ' '; /* pad right with spaces */ 335 } 336 } 337 static inline bool machine_get_squash_mcss(Object *obj, Error **errp) 338 { 339 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 340 341 return ms->s390_squash_mcss; 342 } 343 344 static inline void machine_set_squash_mcss(Object *obj, bool value, 345 Error **errp) 346 { 347 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 348 349 ms->s390_squash_mcss = value; 350 } 351 352 static inline void s390_machine_initfn(Object *obj) 353 { 354 object_property_add_bool(obj, "aes-key-wrap", 355 machine_get_aes_key_wrap, 356 machine_set_aes_key_wrap, NULL); 357 object_property_set_description(obj, "aes-key-wrap", 358 "enable/disable AES key wrapping using the CPACF wrapping key", 359 NULL); 360 object_property_set_bool(obj, true, "aes-key-wrap", NULL); 361 362 object_property_add_bool(obj, "dea-key-wrap", 363 machine_get_dea_key_wrap, 364 machine_set_dea_key_wrap, NULL); 365 object_property_set_description(obj, "dea-key-wrap", 366 "enable/disable DEA key wrapping using the CPACF wrapping key", 367 NULL); 368 object_property_set_bool(obj, true, "dea-key-wrap", NULL); 369 object_property_add_str(obj, "loadparm", 370 machine_get_loadparm, machine_set_loadparm, NULL); 371 object_property_set_description(obj, "loadparm", 372 "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted" 373 " to upper case) to pass to machine loader, boot manager," 374 " and guest kernel", 375 NULL); 376 object_property_add_bool(obj, "s390-squash-mcss", 377 machine_get_squash_mcss, 378 machine_set_squash_mcss, NULL); 379 object_property_set_description(obj, "s390-squash-mcss", 380 "enable/disable squashing subchannels into the default css", 381 NULL); 382 object_property_set_bool(obj, false, "s390-squash-mcss", NULL); 383 } 384 385 static const TypeInfo ccw_machine_info = { 386 .name = TYPE_S390_CCW_MACHINE, 387 .parent = TYPE_MACHINE, 388 .abstract = true, 389 .instance_size = sizeof(S390CcwMachineState), 390 .instance_init = s390_machine_initfn, 391 .class_size = sizeof(S390CcwMachineClass), 392 .class_init = ccw_machine_class_init, 393 .interfaces = (InterfaceInfo[]) { 394 { TYPE_NMI }, 395 { TYPE_HOTPLUG_HANDLER}, 396 { } 397 }, 398 }; 399 400 bool css_migration_enabled(void) 401 { 402 return get_machine_class()->css_migration_enabled; 403 } 404 405 #define DEFINE_CCW_MACHINE(suffix, verstr, latest) \ 406 static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \ 407 void *data) \ 408 { \ 409 MachineClass *mc = MACHINE_CLASS(oc); \ 410 ccw_machine_##suffix##_class_options(mc); \ 411 mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ 412 if (latest) { \ 413 mc->alias = "s390-ccw-virtio"; \ 414 mc->is_default = 1; \ 415 } \ 416 } \ 417 static void ccw_machine_##suffix##_instance_init(Object *obj) \ 418 { \ 419 MachineState *machine = MACHINE(obj); \ 420 current_mc = S390_MACHINE_CLASS(MACHINE_GET_CLASS(machine)); \ 421 ccw_machine_##suffix##_instance_options(machine); \ 422 } \ 423 static const TypeInfo ccw_machine_##suffix##_info = { \ 424 .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \ 425 .parent = TYPE_S390_CCW_MACHINE, \ 426 .class_init = ccw_machine_##suffix##_class_init, \ 427 .instance_init = ccw_machine_##suffix##_instance_init, \ 428 }; \ 429 static void ccw_machine_register_##suffix(void) \ 430 { \ 431 type_register_static(&ccw_machine_##suffix##_info); \ 432 } \ 433 type_init(ccw_machine_register_##suffix) 434 435 #define CCW_COMPAT_2_9 \ 436 HW_COMPAT_2_9 \ 437 {\ 438 .driver = TYPE_S390_STATTRIB,\ 439 .property = "migration-enabled",\ 440 .value = "off",\ 441 }, 442 443 #define CCW_COMPAT_2_8 \ 444 HW_COMPAT_2_8 \ 445 {\ 446 .driver = TYPE_S390_FLIC_COMMON,\ 447 .property = "adapter_routes_max_batch",\ 448 .value = "64",\ 449 }, 450 451 #define CCW_COMPAT_2_7 \ 452 HW_COMPAT_2_7 453 454 #define CCW_COMPAT_2_6 \ 455 HW_COMPAT_2_6 \ 456 {\ 457 .driver = TYPE_S390_IPL,\ 458 .property = "iplbext_migration",\ 459 .value = "off",\ 460 }, {\ 461 .driver = TYPE_VIRTUAL_CSS_BRIDGE,\ 462 .property = "css_dev_path",\ 463 .value = "off",\ 464 }, 465 466 #define CCW_COMPAT_2_5 \ 467 HW_COMPAT_2_5 468 469 #define CCW_COMPAT_2_4 \ 470 HW_COMPAT_2_4 \ 471 {\ 472 .driver = TYPE_S390_SKEYS,\ 473 .property = "migration-enabled",\ 474 .value = "off",\ 475 },{\ 476 .driver = "virtio-blk-ccw",\ 477 .property = "max_revision",\ 478 .value = "0",\ 479 },{\ 480 .driver = "virtio-balloon-ccw",\ 481 .property = "max_revision",\ 482 .value = "0",\ 483 },{\ 484 .driver = "virtio-serial-ccw",\ 485 .property = "max_revision",\ 486 .value = "0",\ 487 },{\ 488 .driver = "virtio-9p-ccw",\ 489 .property = "max_revision",\ 490 .value = "0",\ 491 },{\ 492 .driver = "virtio-rng-ccw",\ 493 .property = "max_revision",\ 494 .value = "0",\ 495 },{\ 496 .driver = "virtio-net-ccw",\ 497 .property = "max_revision",\ 498 .value = "0",\ 499 },{\ 500 .driver = "virtio-scsi-ccw",\ 501 .property = "max_revision",\ 502 .value = "0",\ 503 },{\ 504 .driver = "vhost-scsi-ccw",\ 505 .property = "max_revision",\ 506 .value = "0",\ 507 }, 508 509 static void ccw_machine_2_10_instance_options(MachineState *machine) 510 { 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 } 519 DEFINE_CCW_MACHINE(2_10, "2.10", true); 520 521 static void ccw_machine_2_9_instance_options(MachineState *machine) 522 { 523 ccw_machine_2_10_instance_options(machine); 524 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP); 525 s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2); 526 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI); 527 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION); 528 s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION); 529 } 530 531 static void ccw_machine_2_9_class_options(MachineClass *mc) 532 { 533 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 534 535 s390mc->gs_allowed = false; 536 ccw_machine_2_10_class_options(mc); 537 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9); 538 s390mc->css_migration_enabled = false; 539 } 540 DEFINE_CCW_MACHINE(2_9, "2.9", false); 541 542 static void ccw_machine_2_8_instance_options(MachineState *machine) 543 { 544 ccw_machine_2_9_instance_options(machine); 545 } 546 547 static void ccw_machine_2_8_class_options(MachineClass *mc) 548 { 549 ccw_machine_2_9_class_options(mc); 550 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_8); 551 } 552 DEFINE_CCW_MACHINE(2_8, "2.8", false); 553 554 static void ccw_machine_2_7_instance_options(MachineState *machine) 555 { 556 ccw_machine_2_8_instance_options(machine); 557 } 558 559 static void ccw_machine_2_7_class_options(MachineClass *mc) 560 { 561 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 562 563 s390mc->cpu_model_allowed = false; 564 ccw_machine_2_8_class_options(mc); 565 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7); 566 } 567 DEFINE_CCW_MACHINE(2_7, "2.7", false); 568 569 static void ccw_machine_2_6_instance_options(MachineState *machine) 570 { 571 ccw_machine_2_7_instance_options(machine); 572 } 573 574 static void ccw_machine_2_6_class_options(MachineClass *mc) 575 { 576 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 577 578 s390mc->ri_allowed = false; 579 ccw_machine_2_7_class_options(mc); 580 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6); 581 } 582 DEFINE_CCW_MACHINE(2_6, "2.6", false); 583 584 static void ccw_machine_2_5_instance_options(MachineState *machine) 585 { 586 ccw_machine_2_6_instance_options(machine); 587 } 588 589 static void ccw_machine_2_5_class_options(MachineClass *mc) 590 { 591 ccw_machine_2_6_class_options(mc); 592 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5); 593 } 594 DEFINE_CCW_MACHINE(2_5, "2.5", false); 595 596 static void ccw_machine_2_4_instance_options(MachineState *machine) 597 { 598 ccw_machine_2_5_instance_options(machine); 599 } 600 601 static void ccw_machine_2_4_class_options(MachineClass *mc) 602 { 603 ccw_machine_2_5_class_options(mc); 604 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4); 605 } 606 DEFINE_CCW_MACHINE(2_4, "2.4", false); 607 608 static void ccw_machine_register_types(void) 609 { 610 type_register_static(&ccw_machine_info); 611 } 612 613 type_init(ccw_machine_register_types) 614