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 s390_flic_init(); 126 127 /* get a BUS */ 128 css_bus = virtual_css_bus_init(); 129 s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, 130 machine->initrd_filename, "s390-ccw.img", 131 "s390-netboot.img", true); 132 133 dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); 134 object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, 135 OBJECT(dev), NULL); 136 qdev_init_nofail(dev); 137 138 /* register hypercalls */ 139 virtio_ccw_register_hcalls(); 140 141 /* init CPUs */ 142 s390_init_cpus(machine); 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 mc->init = ccw_init; 213 mc->reset = s390_machine_reset; 214 mc->hot_add_cpu = s390_hot_add_cpu; 215 mc->block_default_type = IF_VIRTIO; 216 mc->no_cdrom = 1; 217 mc->no_floppy = 1; 218 mc->no_serial = 1; 219 mc->no_parallel = 1; 220 mc->no_sdcard = 1; 221 mc->use_sclp = 1; 222 mc->max_cpus = 248; 223 mc->get_hotplug_handler = s390_get_hotplug_handler; 224 hc->plug = s390_machine_device_plug; 225 nc->nmi_monitor_handler = s390_nmi; 226 } 227 228 static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp) 229 { 230 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 231 232 return ms->aes_key_wrap; 233 } 234 235 static inline void machine_set_aes_key_wrap(Object *obj, bool value, 236 Error **errp) 237 { 238 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 239 240 ms->aes_key_wrap = value; 241 } 242 243 static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp) 244 { 245 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 246 247 return ms->dea_key_wrap; 248 } 249 250 static inline void machine_set_dea_key_wrap(Object *obj, bool value, 251 Error **errp) 252 { 253 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 254 255 ms->dea_key_wrap = value; 256 } 257 258 bool ri_allowed(void) 259 { 260 if (kvm_enabled()) { 261 MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); 262 if (object_class_dynamic_cast(OBJECT_CLASS(mc), 263 TYPE_S390_CCW_MACHINE)) { 264 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 265 266 return s390mc->ri_allowed; 267 } 268 /* 269 * Make sure the "none" machine can have ri, otherwise it won't * be 270 * unlocked in KVM and therefore the host CPU model might be wrong. 271 */ 272 return true; 273 } 274 return 0; 275 } 276 277 bool cpu_model_allowed(void) 278 { 279 MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); 280 if (object_class_dynamic_cast(OBJECT_CLASS(mc), 281 TYPE_S390_CCW_MACHINE)) { 282 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 283 284 return s390mc->cpu_model_allowed; 285 } 286 /* allow CPU model qmp queries with the "none" machine */ 287 return true; 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 #define DEFINE_CCW_MACHINE(suffix, verstr, latest) \ 383 static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \ 384 void *data) \ 385 { \ 386 MachineClass *mc = MACHINE_CLASS(oc); \ 387 ccw_machine_##suffix##_class_options(mc); \ 388 mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ 389 if (latest) { \ 390 mc->alias = "s390-ccw-virtio"; \ 391 mc->is_default = 1; \ 392 } \ 393 } \ 394 static void ccw_machine_##suffix##_instance_init(Object *obj) \ 395 { \ 396 MachineState *machine = MACHINE(obj); \ 397 ccw_machine_##suffix##_instance_options(machine); \ 398 } \ 399 static const TypeInfo ccw_machine_##suffix##_info = { \ 400 .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \ 401 .parent = TYPE_S390_CCW_MACHINE, \ 402 .class_init = ccw_machine_##suffix##_class_init, \ 403 .instance_init = ccw_machine_##suffix##_instance_init, \ 404 }; \ 405 static void ccw_machine_register_##suffix(void) \ 406 { \ 407 type_register_static(&ccw_machine_##suffix##_info); \ 408 } \ 409 type_init(ccw_machine_register_##suffix) 410 411 #define CCW_COMPAT_2_9 \ 412 HW_COMPAT_2_9 \ 413 {\ 414 .driver = TYPE_S390_STATTRIB,\ 415 .property = "migration-enabled",\ 416 .value = "off",\ 417 }, 418 419 #define CCW_COMPAT_2_8 \ 420 HW_COMPAT_2_8 \ 421 {\ 422 .driver = TYPE_S390_FLIC_COMMON,\ 423 .property = "adapter_routes_max_batch",\ 424 .value = "64",\ 425 }, 426 427 #define CCW_COMPAT_2_7 \ 428 HW_COMPAT_2_7 429 430 #define CCW_COMPAT_2_6 \ 431 HW_COMPAT_2_6 \ 432 {\ 433 .driver = TYPE_S390_IPL,\ 434 .property = "iplbext_migration",\ 435 .value = "off",\ 436 }, {\ 437 .driver = TYPE_VIRTUAL_CSS_BRIDGE,\ 438 .property = "css_dev_path",\ 439 .value = "off",\ 440 }, 441 442 #define CCW_COMPAT_2_5 \ 443 HW_COMPAT_2_5 444 445 #define CCW_COMPAT_2_4 \ 446 HW_COMPAT_2_4 \ 447 {\ 448 .driver = TYPE_S390_SKEYS,\ 449 .property = "migration-enabled",\ 450 .value = "off",\ 451 },{\ 452 .driver = "virtio-blk-ccw",\ 453 .property = "max_revision",\ 454 .value = "0",\ 455 },{\ 456 .driver = "virtio-balloon-ccw",\ 457 .property = "max_revision",\ 458 .value = "0",\ 459 },{\ 460 .driver = "virtio-serial-ccw",\ 461 .property = "max_revision",\ 462 .value = "0",\ 463 },{\ 464 .driver = "virtio-9p-ccw",\ 465 .property = "max_revision",\ 466 .value = "0",\ 467 },{\ 468 .driver = "virtio-rng-ccw",\ 469 .property = "max_revision",\ 470 .value = "0",\ 471 },{\ 472 .driver = "virtio-net-ccw",\ 473 .property = "max_revision",\ 474 .value = "0",\ 475 },{\ 476 .driver = "virtio-scsi-ccw",\ 477 .property = "max_revision",\ 478 .value = "0",\ 479 },{\ 480 .driver = "vhost-scsi-ccw",\ 481 .property = "max_revision",\ 482 .value = "0",\ 483 }, 484 485 static void ccw_machine_2_10_instance_options(MachineState *machine) 486 { 487 } 488 489 static void ccw_machine_2_10_class_options(MachineClass *mc) 490 { 491 } 492 DEFINE_CCW_MACHINE(2_10, "2.10", true); 493 494 static void ccw_machine_2_9_instance_options(MachineState *machine) 495 { 496 ccw_machine_2_10_instance_options(machine); 497 } 498 499 static void ccw_machine_2_9_class_options(MachineClass *mc) 500 { 501 ccw_machine_2_10_class_options(mc); 502 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9); 503 } 504 DEFINE_CCW_MACHINE(2_9, "2.9", false); 505 506 static void ccw_machine_2_8_instance_options(MachineState *machine) 507 { 508 ccw_machine_2_9_instance_options(machine); 509 } 510 511 static void ccw_machine_2_8_class_options(MachineClass *mc) 512 { 513 ccw_machine_2_9_class_options(mc); 514 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_8); 515 } 516 DEFINE_CCW_MACHINE(2_8, "2.8", false); 517 518 static void ccw_machine_2_7_instance_options(MachineState *machine) 519 { 520 ccw_machine_2_8_instance_options(machine); 521 } 522 523 static void ccw_machine_2_7_class_options(MachineClass *mc) 524 { 525 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 526 527 s390mc->cpu_model_allowed = false; 528 ccw_machine_2_8_class_options(mc); 529 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7); 530 } 531 DEFINE_CCW_MACHINE(2_7, "2.7", false); 532 533 static void ccw_machine_2_6_instance_options(MachineState *machine) 534 { 535 ccw_machine_2_7_instance_options(machine); 536 } 537 538 static void ccw_machine_2_6_class_options(MachineClass *mc) 539 { 540 S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); 541 542 s390mc->ri_allowed = false; 543 ccw_machine_2_7_class_options(mc); 544 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6); 545 } 546 DEFINE_CCW_MACHINE(2_6, "2.6", false); 547 548 static void ccw_machine_2_5_instance_options(MachineState *machine) 549 { 550 ccw_machine_2_6_instance_options(machine); 551 } 552 553 static void ccw_machine_2_5_class_options(MachineClass *mc) 554 { 555 ccw_machine_2_6_class_options(mc); 556 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5); 557 } 558 DEFINE_CCW_MACHINE(2_5, "2.5", false); 559 560 static void ccw_machine_2_4_instance_options(MachineState *machine) 561 { 562 ccw_machine_2_5_instance_options(machine); 563 } 564 565 static void ccw_machine_2_4_class_options(MachineClass *mc) 566 { 567 ccw_machine_2_5_class_options(mc); 568 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4); 569 } 570 DEFINE_CCW_MACHINE(2_4, "2.4", false); 571 572 static void ccw_machine_register_types(void) 573 { 574 type_register_static(&ccw_machine_info); 575 } 576 577 type_init(ccw_machine_register_types) 578