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