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 "hw/boards.h" 14 #include "exec/address-spaces.h" 15 #include "s390-virtio.h" 16 #include "hw/s390x/sclp.h" 17 #include "hw/s390x/s390_flic.h" 18 #include "ioinst.h" 19 #include "css.h" 20 #include "virtio-ccw.h" 21 #include "qemu/config-file.h" 22 #include "s390-pci-bus.h" 23 #include "hw/s390x/storage-keys.h" 24 #include "hw/compat.h" 25 #include "hw/s390x/s390-virtio-ccw.h" 26 27 static const char *const reset_dev_types[] = { 28 "virtual-css-bridge", 29 "s390-sclp-event-facility", 30 "s390-flic", 31 "diag288", 32 }; 33 34 void subsystem_reset(void) 35 { 36 DeviceState *dev; 37 int i; 38 39 for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) { 40 dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL)); 41 if (dev) { 42 qdev_reset_all(dev); 43 } 44 } 45 } 46 47 static int virtio_ccw_hcall_notify(const uint64_t *args) 48 { 49 uint64_t subch_id = args[0]; 50 uint64_t queue = args[1]; 51 SubchDev *sch; 52 int cssid, ssid, schid, m; 53 54 if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) { 55 return -EINVAL; 56 } 57 sch = css_find_subch(m, cssid, ssid, schid); 58 if (!sch || !css_subch_visible(sch)) { 59 return -EINVAL; 60 } 61 if (queue >= VIRTIO_CCW_QUEUE_MAX) { 62 return -EINVAL; 63 } 64 virtio_queue_notify(virtio_ccw_get_vdev(sch), queue); 65 return 0; 66 67 } 68 69 static int virtio_ccw_hcall_early_printk(const uint64_t *args) 70 { 71 uint64_t mem = args[0]; 72 73 if (mem < ram_size) { 74 /* Early printk */ 75 return 0; 76 } 77 return -EINVAL; 78 } 79 80 static void virtio_ccw_register_hcalls(void) 81 { 82 s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, 83 virtio_ccw_hcall_notify); 84 /* Tolerate early printk. */ 85 s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY, 86 virtio_ccw_hcall_early_printk); 87 } 88 89 void s390_memory_init(ram_addr_t mem_size) 90 { 91 MemoryRegion *sysmem = get_system_memory(); 92 MemoryRegion *ram = g_new(MemoryRegion, 1); 93 94 /* allocate RAM for core */ 95 memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size); 96 memory_region_add_subregion(sysmem, 0, ram); 97 98 /* Initialize storage key device */ 99 s390_skeys_init(); 100 } 101 102 static void ccw_init(MachineState *machine) 103 { 104 int ret; 105 VirtualCssBus *css_bus; 106 DeviceState *dev; 107 108 s390_sclp_init(); 109 s390_memory_init(machine->ram_size); 110 111 /* get a BUS */ 112 css_bus = virtual_css_bus_init(); 113 s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, 114 machine->initrd_filename, "s390-ccw.img", true); 115 s390_flic_init(); 116 117 dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); 118 object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, 119 OBJECT(dev), NULL); 120 qdev_init_nofail(dev); 121 122 /* register hypercalls */ 123 virtio_ccw_register_hcalls(); 124 125 /* init CPUs */ 126 s390_init_cpus(machine); 127 128 if (kvm_enabled()) { 129 kvm_s390_enable_css_support(s390_cpu_addr2state(0)); 130 } 131 /* 132 * Create virtual css and set it as default so that non mcss-e 133 * enabled guests only see virtio devices. 134 */ 135 ret = css_create_css_image(VIRTUAL_CSSID, true); 136 assert(ret == 0); 137 138 /* Create VirtIO network adapters */ 139 s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); 140 141 /* Register savevm handler for guest TOD clock */ 142 register_savevm(NULL, "todclock", 0, 1, 143 gtod_save, gtod_load, kvm_state); 144 } 145 146 static void s390_cpu_plug(HotplugHandler *hotplug_dev, 147 DeviceState *dev, Error **errp) 148 { 149 gchar *name; 150 S390CPU *cpu = S390_CPU(dev); 151 CPUState *cs = CPU(dev); 152 153 name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num); 154 object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name, 155 errp); 156 g_free(name); 157 } 158 159 static void s390_machine_device_plug(HotplugHandler *hotplug_dev, 160 DeviceState *dev, Error **errp) 161 { 162 if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 163 s390_cpu_plug(hotplug_dev, dev, errp); 164 } 165 } 166 167 static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, 168 DeviceState *dev) 169 { 170 if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 171 return HOTPLUG_HANDLER(machine); 172 } 173 return NULL; 174 } 175 176 static void s390_hot_add_cpu(const int64_t id, Error **errp) 177 { 178 MachineState *machine = MACHINE(qdev_get_machine()); 179 Error *err = NULL; 180 181 s390x_new_cpu(machine->cpu_model, id, &err); 182 error_propagate(errp, err); 183 } 184 185 static void ccw_machine_class_init(ObjectClass *oc, void *data) 186 { 187 MachineClass *mc = MACHINE_CLASS(oc); 188 NMIClass *nc = NMI_CLASS(oc); 189 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); 190 191 mc->init = ccw_init; 192 mc->reset = s390_machine_reset; 193 mc->hot_add_cpu = s390_hot_add_cpu; 194 mc->block_default_type = IF_VIRTIO; 195 mc->no_cdrom = 1; 196 mc->no_floppy = 1; 197 mc->no_serial = 1; 198 mc->no_parallel = 1; 199 mc->no_sdcard = 1; 200 mc->use_sclp = 1; 201 mc->max_cpus = 255; 202 mc->get_hotplug_handler = s390_get_hotplug_handler; 203 hc->plug = s390_machine_device_plug; 204 nc->nmi_monitor_handler = s390_nmi; 205 } 206 207 static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp) 208 { 209 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 210 211 return ms->aes_key_wrap; 212 } 213 214 static inline void machine_set_aes_key_wrap(Object *obj, bool value, 215 Error **errp) 216 { 217 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 218 219 ms->aes_key_wrap = value; 220 } 221 222 static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp) 223 { 224 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 225 226 return ms->dea_key_wrap; 227 } 228 229 static inline void machine_set_dea_key_wrap(Object *obj, bool value, 230 Error **errp) 231 { 232 S390CcwMachineState *ms = S390_CCW_MACHINE(obj); 233 234 ms->dea_key_wrap = value; 235 } 236 237 static inline void s390_machine_initfn(Object *obj) 238 { 239 object_property_add_bool(obj, "aes-key-wrap", 240 machine_get_aes_key_wrap, 241 machine_set_aes_key_wrap, NULL); 242 object_property_set_description(obj, "aes-key-wrap", 243 "enable/disable AES key wrapping using the CPACF wrapping key", 244 NULL); 245 object_property_set_bool(obj, true, "aes-key-wrap", NULL); 246 247 object_property_add_bool(obj, "dea-key-wrap", 248 machine_get_dea_key_wrap, 249 machine_set_dea_key_wrap, NULL); 250 object_property_set_description(obj, "dea-key-wrap", 251 "enable/disable DEA key wrapping using the CPACF wrapping key", 252 NULL); 253 object_property_set_bool(obj, true, "dea-key-wrap", NULL); 254 } 255 256 static const TypeInfo ccw_machine_info = { 257 .name = TYPE_S390_CCW_MACHINE, 258 .parent = TYPE_MACHINE, 259 .abstract = true, 260 .instance_size = sizeof(S390CcwMachineState), 261 .instance_init = s390_machine_initfn, 262 .class_init = ccw_machine_class_init, 263 .interfaces = (InterfaceInfo[]) { 264 { TYPE_NMI }, 265 { TYPE_HOTPLUG_HANDLER}, 266 { } 267 }, 268 }; 269 270 #define DEFINE_CCW_MACHINE(suffix, verstr, latest) \ 271 static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \ 272 void *data) \ 273 { \ 274 MachineClass *mc = MACHINE_CLASS(oc); \ 275 ccw_machine_##suffix##_class_options(mc); \ 276 mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ 277 if (latest) { \ 278 mc->alias = "s390-ccw-virtio"; \ 279 mc->is_default = 1; \ 280 } \ 281 } \ 282 static void ccw_machine_##suffix##_instance_init(Object *obj) \ 283 { \ 284 MachineState *machine = MACHINE(obj); \ 285 ccw_machine_##suffix##_instance_options(machine); \ 286 } \ 287 static const TypeInfo ccw_machine_##suffix##_info = { \ 288 .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \ 289 .parent = TYPE_S390_CCW_MACHINE, \ 290 .class_init = ccw_machine_##suffix##_class_init, \ 291 .instance_init = ccw_machine_##suffix##_instance_init, \ 292 }; \ 293 static void ccw_machine_register_##suffix(void) \ 294 { \ 295 type_register_static(&ccw_machine_##suffix##_info); \ 296 } \ 297 type_init(ccw_machine_register_##suffix) 298 299 #define CCW_COMPAT_2_5 \ 300 HW_COMPAT_2_5 301 302 #define CCW_COMPAT_2_4 \ 303 CCW_COMPAT_2_5 \ 304 HW_COMPAT_2_4 \ 305 {\ 306 .driver = TYPE_S390_SKEYS,\ 307 .property = "migration-enabled",\ 308 .value = "off",\ 309 },{\ 310 .driver = "virtio-blk-ccw",\ 311 .property = "max_revision",\ 312 .value = "0",\ 313 },{\ 314 .driver = "virtio-balloon-ccw",\ 315 .property = "max_revision",\ 316 .value = "0",\ 317 },{\ 318 .driver = "virtio-serial-ccw",\ 319 .property = "max_revision",\ 320 .value = "0",\ 321 },{\ 322 .driver = "virtio-9p-ccw",\ 323 .property = "max_revision",\ 324 .value = "0",\ 325 },{\ 326 .driver = "virtio-rng-ccw",\ 327 .property = "max_revision",\ 328 .value = "0",\ 329 },{\ 330 .driver = "virtio-net-ccw",\ 331 .property = "max_revision",\ 332 .value = "0",\ 333 },{\ 334 .driver = "virtio-scsi-ccw",\ 335 .property = "max_revision",\ 336 .value = "0",\ 337 },{\ 338 .driver = "vhost-scsi-ccw",\ 339 .property = "max_revision",\ 340 .value = "0",\ 341 }, 342 343 static void ccw_machine_2_6_instance_options(MachineState *machine) 344 { 345 } 346 347 static void ccw_machine_2_6_class_options(MachineClass *mc) 348 { 349 } 350 DEFINE_CCW_MACHINE(2_6, "2.6", true); 351 352 static void ccw_machine_2_5_instance_options(MachineState *machine) 353 { 354 } 355 356 static void ccw_machine_2_5_class_options(MachineClass *mc) 357 { 358 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5); 359 } 360 DEFINE_CCW_MACHINE(2_5, "2.5", false); 361 362 static void ccw_machine_2_4_instance_options(MachineState *machine) 363 { 364 ccw_machine_2_5_instance_options(machine); 365 } 366 367 static void ccw_machine_2_4_class_options(MachineClass *mc) 368 { 369 SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4); 370 } 371 DEFINE_CCW_MACHINE(2_4, "2.4", false); 372 373 static void ccw_machine_register_types(void) 374 { 375 type_register_static(&ccw_machine_info); 376 } 377 378 type_init(ccw_machine_register_types) 379