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