]>
Commit | Line | Data |
---|---|---|
a5c95808 CH |
1 | /* |
2 | * virtio ccw machine | |
3 | * | |
4 | * Copyright 2012 IBM Corp. | |
6286b419 | 5 | * Copyright (c) 2009 Alexander Graf <[email protected]> |
a5c95808 CH |
6 | * Author(s): Cornelia Huck <[email protected]> |
7 | * | |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or (at | |
9 | * your option) any later version. See the COPYING file in the top-level | |
10 | * directory. | |
11 | */ | |
12 | ||
9615495a | 13 | #include "qemu/osdep.h" |
da34e65c | 14 | #include "qapi/error.h" |
4771d756 | 15 | #include "cpu.h" |
a5c95808 CH |
16 | #include "hw/boards.h" |
17 | #include "exec/address-spaces.h" | |
7d577546 | 18 | #include "hw/s390x/s390-virtio-hcall.h" |
83c9f4ca | 19 | #include "hw/s390x/sclp.h" |
3a553fc6 | 20 | #include "hw/s390x/s390_flic.h" |
bd3f16ac PB |
21 | #include "hw/s390x/ioinst.h" |
22 | #include "hw/s390x/css.h" | |
a5c95808 | 23 | #include "virtio-ccw.h" |
b6fe0124 | 24 | #include "qemu/config-file.h" |
b5684cd8 | 25 | #include "qemu/error-report.h" |
922a01a0 | 26 | #include "qemu/option.h" |
8cba80c3 | 27 | #include "s390-pci-bus.h" |
0f5f6691 | 28 | #include "hw/s390x/storage-keys.h" |
903fd80b | 29 | #include "hw/s390x/storage-attributes.h" |
bc61c8c6 | 30 | #include "hw/s390x/event-facility.h" |
54d8ec84 | 31 | #include "hw/compat.h" |
04ca4b92 | 32 | #include "ipl.h" |
8b8a61ad | 33 | #include "hw/s390x/s390-virtio-ccw.h" |
dd70bd0d | 34 | #include "hw/s390x/css-bridge.h" |
f2a8f0a6 | 35 | #include "migration/register.h" |
7223bcce | 36 | #include "cpu_models.h" |
6286b419 DH |
37 | #include "hw/nmi.h" |
38 | ||
6286b419 DH |
39 | S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) |
40 | { | |
2b44178d DH |
41 | static MachineState *ms; |
42 | ||
43 | if (!ms) { | |
44 | ms = MACHINE(qdev_get_machine()); | |
45 | g_assert(ms->possible_cpus); | |
6286b419 DH |
46 | } |
47 | ||
2b44178d DH |
48 | /* CPU address corresponds to the core_id and the index */ |
49 | if (cpu_addr >= ms->possible_cpus->len) { | |
50 | return NULL; | |
51 | } | |
52 | return S390_CPU(ms->possible_cpus->cpus[cpu_addr].cpu); | |
6286b419 DH |
53 | } |
54 | ||
32dc6aa0 IM |
55 | static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, |
56 | Error **errp) | |
57 | { | |
58 | S390CPU *cpu = S390_CPU(object_new(typename)); | |
59 | Error *err = NULL; | |
60 | ||
61 | object_property_set_int(OBJECT(cpu), core_id, "core-id", &err); | |
62 | if (err != NULL) { | |
63 | goto out; | |
64 | } | |
65 | object_property_set_bool(OBJECT(cpu), true, "realized", &err); | |
66 | ||
67 | out: | |
68 | object_unref(OBJECT(cpu)); | |
69 | if (err) { | |
70 | error_propagate(errp, err); | |
71 | cpu = NULL; | |
72 | } | |
73 | return cpu; | |
74 | } | |
75 | ||
6286b419 DH |
76 | static void s390_init_cpus(MachineState *machine) |
77 | { | |
4dc3b151 | 78 | MachineClass *mc = MACHINE_GET_CLASS(machine); |
6286b419 | 79 | int i; |
6286b419 | 80 | |
4dc3b151 DH |
81 | /* initialize possible_cpus */ |
82 | mc->possible_cpu_arch_ids(machine); | |
83 | ||
6286b419 | 84 | for (i = 0; i < smp_cpus; i++) { |
b6805e12 | 85 | s390x_new_cpu(machine->cpu_type, i, &error_fatal); |
6286b419 DH |
86 | } |
87 | } | |
2eb1cd07 | 88 | |
09c7f58c | 89 | static const char *const reset_dev_types[] = { |
3f9e4859 | 90 | TYPE_VIRTUAL_CSS_BRIDGE, |
09c7f58c DH |
91 | "s390-sclp-event-facility", |
92 | "s390-flic", | |
93 | "diag288", | |
94 | }; | |
95 | ||
a30fb811 | 96 | static void subsystem_reset(void) |
4e872a3f | 97 | { |
09c7f58c DH |
98 | DeviceState *dev; |
99 | int i; | |
4e872a3f | 100 | |
09c7f58c DH |
101 | for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) { |
102 | dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL)); | |
103 | if (dev) { | |
104 | qdev_reset_all(dev); | |
105 | } | |
0c7322cf | 106 | } |
4e872a3f CB |
107 | } |
108 | ||
a5c95808 CH |
109 | static int virtio_ccw_hcall_notify(const uint64_t *args) |
110 | { | |
111 | uint64_t subch_id = args[0]; | |
112 | uint64_t queue = args[1]; | |
113 | SubchDev *sch; | |
114 | int cssid, ssid, schid, m; | |
115 | ||
116 | if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) { | |
117 | return -EINVAL; | |
118 | } | |
119 | sch = css_find_subch(m, cssid, ssid, schid); | |
120 | if (!sch || !css_subch_visible(sch)) { | |
121 | return -EINVAL; | |
122 | } | |
b1914b82 | 123 | if (queue >= VIRTIO_QUEUE_MAX) { |
b57ed9bf CH |
124 | return -EINVAL; |
125 | } | |
a5c95808 CH |
126 | virtio_queue_notify(virtio_ccw_get_vdev(sch), queue); |
127 | return 0; | |
128 | ||
129 | } | |
130 | ||
131 | static int virtio_ccw_hcall_early_printk(const uint64_t *args) | |
132 | { | |
133 | uint64_t mem = args[0]; | |
134 | ||
135 | if (mem < ram_size) { | |
136 | /* Early printk */ | |
137 | return 0; | |
138 | } | |
139 | return -EINVAL; | |
140 | } | |
141 | ||
142 | static void virtio_ccw_register_hcalls(void) | |
143 | { | |
144 | s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, | |
145 | virtio_ccw_hcall_notify); | |
146 | /* Tolerate early printk. */ | |
147 | s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY, | |
148 | virtio_ccw_hcall_early_printk); | |
149 | } | |
150 | ||
bb223055 CB |
151 | /* |
152 | * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages | |
153 | * as the dirty bitmap must be managed by bitops that take an int as | |
154 | * position indicator. If we have a guest beyond that we will split off | |
155 | * new subregions. The split must happen on a segment boundary (1MB). | |
156 | */ | |
157 | #define KVM_MEM_MAX_NR_PAGES ((1ULL << 31) - 1) | |
158 | #define SEG_MSK (~0xfffffULL) | |
159 | #define KVM_SLOT_MAX_BYTES ((KVM_MEM_MAX_NR_PAGES * TARGET_PAGE_SIZE) & SEG_MSK) | |
6286b419 | 160 | static void s390_memory_init(ram_addr_t mem_size) |
a5c95808 | 161 | { |
a5c95808 | 162 | MemoryRegion *sysmem = get_system_memory(); |
bb223055 CB |
163 | ram_addr_t chunk, offset = 0; |
164 | unsigned int number = 0; | |
165 | gchar *name; | |
80d23275 DH |
166 | |
167 | /* allocate RAM for core */ | |
bb223055 CB |
168 | name = g_strdup_printf("s390.ram"); |
169 | while (mem_size) { | |
170 | MemoryRegion *ram = g_new(MemoryRegion, 1); | |
171 | uint64_t size = mem_size; | |
172 | ||
173 | /* KVM does not allow memslots >= 8 TB */ | |
174 | chunk = MIN(size, KVM_SLOT_MAX_BYTES); | |
175 | memory_region_allocate_system_memory(ram, NULL, name, chunk); | |
176 | memory_region_add_subregion(sysmem, offset, ram); | |
177 | mem_size -= chunk; | |
178 | offset += chunk; | |
179 | g_free(name); | |
180 | name = g_strdup_printf("s390.ram.%u", ++number); | |
181 | } | |
182 | g_free(name); | |
80d23275 DH |
183 | |
184 | /* Initialize storage key device */ | |
185 | s390_skeys_init(); | |
903fd80b CI |
186 | /* Initialize storage attributes device */ |
187 | s390_stattrib_init(); | |
80d23275 DH |
188 | } |
189 | ||
6286b419 DH |
190 | #define S390_TOD_CLOCK_VALUE_MISSING 0x00 |
191 | #define S390_TOD_CLOCK_VALUE_PRESENT 0x01 | |
192 | ||
193 | static void gtod_save(QEMUFile *f, void *opaque) | |
194 | { | |
195 | uint64_t tod_low; | |
196 | uint8_t tod_high; | |
197 | int r; | |
198 | ||
199 | r = s390_get_clock(&tod_high, &tod_low); | |
200 | if (r) { | |
201 | warn_report("Unable to get guest clock for migration: %s", | |
202 | strerror(-r)); | |
203 | error_printf("Guest clock will not be migrated " | |
204 | "which could cause the guest to hang."); | |
205 | qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); | |
206 | return; | |
207 | } | |
208 | ||
209 | qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); | |
210 | qemu_put_byte(f, tod_high); | |
211 | qemu_put_be64(f, tod_low); | |
212 | } | |
213 | ||
214 | static int gtod_load(QEMUFile *f, void *opaque, int version_id) | |
215 | { | |
216 | uint64_t tod_low; | |
217 | uint8_t tod_high; | |
218 | int r; | |
219 | ||
220 | if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { | |
221 | warn_report("Guest clock was not migrated. This could " | |
222 | "cause the guest to hang."); | |
223 | return 0; | |
224 | } | |
225 | ||
226 | tod_high = qemu_get_byte(f); | |
227 | tod_low = qemu_get_be64(f); | |
228 | ||
229 | r = s390_set_clock(&tod_high, &tod_low); | |
230 | if (r) { | |
28f8dbe8 | 231 | error_report("Unable to set KVM guest TOD clock: %s", strerror(-r)); |
6286b419 DH |
232 | } |
233 | ||
28f8dbe8 | 234 | return r; |
6286b419 DH |
235 | } |
236 | ||
1b6e7482 LV |
237 | static SaveVMHandlers savevm_gtod = { |
238 | .save_state = gtod_save, | |
239 | .load_state = gtod_load, | |
240 | }; | |
241 | ||
6286b419 DH |
242 | static void s390_init_ipl_dev(const char *kernel_filename, |
243 | const char *kernel_cmdline, | |
244 | const char *initrd_filename, const char *firmware, | |
245 | const char *netboot_fw, bool enforce_bios) | |
246 | { | |
247 | Object *new = object_new(TYPE_S390_IPL); | |
248 | DeviceState *dev = DEVICE(new); | |
d9b06db8 | 249 | char *netboot_fw_prop; |
6286b419 DH |
250 | |
251 | if (kernel_filename) { | |
252 | qdev_prop_set_string(dev, "kernel", kernel_filename); | |
253 | } | |
254 | if (initrd_filename) { | |
255 | qdev_prop_set_string(dev, "initrd", initrd_filename); | |
256 | } | |
257 | qdev_prop_set_string(dev, "cmdline", kernel_cmdline); | |
258 | qdev_prop_set_string(dev, "firmware", firmware); | |
6286b419 | 259 | qdev_prop_set_bit(dev, "enforce_bios", enforce_bios); |
d9b06db8 GK |
260 | netboot_fw_prop = object_property_get_str(new, "netboot_fw", &error_abort); |
261 | if (!strlen(netboot_fw_prop)) { | |
3c4e9baa TH |
262 | qdev_prop_set_string(dev, "netboot_fw", netboot_fw); |
263 | } | |
d9b06db8 | 264 | g_free(netboot_fw_prop); |
6286b419 DH |
265 | object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, |
266 | new, NULL); | |
267 | object_unref(new); | |
268 | qdev_init_nofail(dev); | |
269 | } | |
270 | ||
271 | static void s390_create_virtio_net(BusState *bus, const char *name) | |
272 | { | |
273 | int i; | |
274 | ||
275 | for (i = 0; i < nb_nics; i++) { | |
276 | NICInfo *nd = &nd_table[i]; | |
277 | DeviceState *dev; | |
278 | ||
279 | if (!nd->model) { | |
280 | nd->model = g_strdup("virtio"); | |
281 | } | |
282 | ||
283 | qemu_check_nic_model(nd, "virtio"); | |
284 | ||
285 | dev = qdev_create(bus, name); | |
286 | qdev_set_nic_properties(dev, nd); | |
287 | qdev_init_nofail(dev); | |
288 | } | |
289 | } | |
290 | ||
052888f0 TH |
291 | static void s390_create_sclpconsole(const char *type, Chardev *chardev) |
292 | { | |
293 | DeviceState *dev; | |
294 | ||
295 | dev = qdev_create(sclp_get_event_facility_bus(), type); | |
296 | qdev_prop_set_chr(dev, "chardev", chardev); | |
297 | qdev_init_nofail(dev); | |
298 | } | |
299 | ||
80d23275 DH |
300 | static void ccw_init(MachineState *machine) |
301 | { | |
a5c95808 CH |
302 | int ret; |
303 | VirtualCssBus *css_bus; | |
c1843e20 | 304 | DeviceState *dev; |
b6fe0124 | 305 | |
1cf065fb | 306 | s390_sclp_init(); |
80d23275 | 307 | s390_memory_init(machine->ram_size); |
a5c95808 | 308 | |
d32bd032 | 309 | /* init CPUs (incl. CPU model) early so s390_has_feature() works */ |
3720d335 YMZ |
310 | s390_init_cpus(machine); |
311 | ||
c572d3f3 FL |
312 | s390_flic_init(); |
313 | ||
74b4c74d DH |
314 | /* init the SIGP facility */ |
315 | s390_init_sigp(); | |
316 | ||
a5c95808 CH |
317 | /* get a BUS */ |
318 | css_bus = virtual_css_bus_init(); | |
3ef96221 | 319 | s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, |
5f31ade0 FA |
320 | machine->initrd_filename, "s390-ccw.img", |
321 | "s390-netboot.img", true); | |
a5c95808 | 322 | |
c1843e20 CB |
323 | /* |
324 | * We cannot easily make the pci host bridge conditional as older QEMUs | |
325 | * always created it. Doing so would break migration across QEMU versions. | |
326 | */ | |
327 | dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); | |
328 | object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, | |
329 | OBJECT(dev), NULL); | |
330 | qdev_init_nofail(dev); | |
8cba80c3 | 331 | |
a5c95808 CH |
332 | /* register hypercalls */ |
333 | virtio_ccw_register_hcalls(); | |
334 | ||
5e7164c5 | 335 | s390_enable_css_support(s390_cpu_addr2state(0)); |
a5c95808 | 336 | /* |
817d4a6b DJS |
337 | * Non mcss-e enabled guests only see the devices from the default |
338 | * css, which is determined by the value of the squash_mcss property. | |
a5c95808 | 339 | */ |
817d4a6b DJS |
340 | if (css_bus->squash_mcss) { |
341 | ret = css_create_css_image(0, true); | |
342 | } else { | |
343 | ret = css_create_css_image(VIRTUAL_CSSID, true); | |
344 | } | |
d69969e5 HP |
345 | if (qemu_opt_get(qemu_get_machine_opts(), "s390-squash-mcss")) { |
346 | warn_report("The machine property 's390-squash-mcss' is deprecated" | |
347 | " (obsoleted by lifting the cssid restrictions)."); | |
348 | } | |
349 | ||
a5c95808 | 350 | assert(ret == 0); |
489c909f HP |
351 | if (css_migration_enabled()) { |
352 | css_register_vmstate(); | |
353 | } | |
a5c95808 CH |
354 | |
355 | /* Create VirtIO network adapters */ | |
356 | s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); | |
3f9e59bb | 357 | |
052888f0 TH |
358 | /* init consoles */ |
359 | if (serial_hd(0)) { | |
360 | s390_create_sclpconsole("sclpconsole", serial_hd(0)); | |
361 | } | |
362 | if (serial_hd(1)) { | |
363 | s390_create_sclpconsole("sclplmconsole", serial_hd(1)); | |
364 | } | |
365 | ||
3f9e59bb | 366 | /* Register savevm handler for guest TOD clock */ |
fe7cb8ea | 367 | register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL); |
a5c95808 CH |
368 | } |
369 | ||
502edbf8 MR |
370 | static void s390_cpu_plug(HotplugHandler *hotplug_dev, |
371 | DeviceState *dev, Error **errp) | |
372 | { | |
4dc3b151 | 373 | MachineState *ms = MACHINE(hotplug_dev); |
502edbf8 | 374 | S390CPU *cpu = S390_CPU(dev); |
4dc3b151 DH |
375 | |
376 | g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu); | |
377 | ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev); | |
c5b93430 DH |
378 | |
379 | if (dev->hotplugged) { | |
380 | raise_irq_cpu_hotplug(); | |
381 | } | |
502edbf8 MR |
382 | } |
383 | ||
a30fb811 DH |
384 | static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg) |
385 | { | |
386 | S390CPU *cpu = S390_CPU(cs); | |
387 | ||
388 | s390_ipl_prepare_cpu(cpu); | |
389 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); | |
390 | } | |
391 | ||
6286b419 DH |
392 | static void s390_machine_reset(void) |
393 | { | |
a30fb811 DH |
394 | enum s390_reset reset_type; |
395 | CPUState *cs, *t; | |
6286b419 | 396 | |
a30fb811 DH |
397 | /* get the reset parameters, reset them once done */ |
398 | s390_ipl_get_reset_request(&cs, &reset_type); | |
399 | ||
400 | /* all CPUs are paused and synchronized at this point */ | |
6286b419 | 401 | s390_cmma_reset(); |
6286b419 | 402 | |
a30fb811 DH |
403 | switch (reset_type) { |
404 | case S390_RESET_EXTERNAL: | |
405 | case S390_RESET_REIPL: | |
406 | qemu_devices_reset(); | |
407 | s390_crypto_reset(); | |
408 | ||
409 | /* configure and start the ipl CPU only */ | |
410 | run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL); | |
411 | break; | |
412 | case S390_RESET_MODIFIED_CLEAR: | |
413 | CPU_FOREACH(t) { | |
414 | run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); | |
415 | } | |
416 | subsystem_reset(); | |
417 | s390_crypto_reset(); | |
418 | run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); | |
419 | break; | |
420 | case S390_RESET_LOAD_NORMAL: | |
421 | CPU_FOREACH(t) { | |
422 | run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL); | |
423 | } | |
424 | subsystem_reset(); | |
425 | run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL); | |
426 | run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); | |
427 | break; | |
428 | default: | |
429 | g_assert_not_reached(); | |
430 | } | |
431 | s390_ipl_clear_reset_request(); | |
6286b419 DH |
432 | } |
433 | ||
502edbf8 MR |
434 | static void s390_machine_device_plug(HotplugHandler *hotplug_dev, |
435 | DeviceState *dev, Error **errp) | |
436 | { | |
437 | if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { | |
438 | s390_cpu_plug(hotplug_dev, dev, errp); | |
439 | } | |
440 | } | |
441 | ||
f2f3beb0 DH |
442 | static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev, |
443 | DeviceState *dev, Error **errp) | |
444 | { | |
445 | if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { | |
446 | error_setg(errp, "CPU hot unplug not supported on this machine"); | |
447 | return; | |
448 | } | |
449 | } | |
450 | ||
81ce6aa5 | 451 | static CpuInstanceProperties s390_cpu_index_to_props(MachineState *ms, |
4dc3b151 DH |
452 | unsigned cpu_index) |
453 | { | |
81ce6aa5 DH |
454 | MachineClass *mc = MACHINE_GET_CLASS(ms); |
455 | const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); | |
4dc3b151 | 456 | |
81ce6aa5 DH |
457 | assert(cpu_index < possible_cpus->len); |
458 | return possible_cpus->cpus[cpu_index].props; | |
4dc3b151 DH |
459 | } |
460 | ||
461 | static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms) | |
462 | { | |
463 | int i; | |
464 | ||
465 | if (ms->possible_cpus) { | |
466 | g_assert(ms->possible_cpus && ms->possible_cpus->len == max_cpus); | |
467 | return ms->possible_cpus; | |
468 | } | |
469 | ||
470 | ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + | |
471 | sizeof(CPUArchId) * max_cpus); | |
472 | ms->possible_cpus->len = max_cpus; | |
473 | for (i = 0; i < ms->possible_cpus->len; i++) { | |
d342eb76 | 474 | ms->possible_cpus->cpus[i].type = ms->cpu_type; |
4dc3b151 DH |
475 | ms->possible_cpus->cpus[i].vcpus_count = 1; |
476 | ms->possible_cpus->cpus[i].arch_id = i; | |
477 | ms->possible_cpus->cpus[i].props.has_core_id = true; | |
478 | ms->possible_cpus->cpus[i].props.core_id = i; | |
479 | } | |
480 | ||
481 | return ms->possible_cpus; | |
482 | } | |
483 | ||
502edbf8 MR |
484 | static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, |
485 | DeviceState *dev) | |
486 | { | |
487 | if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { | |
488 | return HOTPLUG_HANDLER(machine); | |
489 | } | |
490 | return NULL; | |
491 | } | |
492 | ||
a006b67f MR |
493 | static void s390_hot_add_cpu(const int64_t id, Error **errp) |
494 | { | |
495 | MachineState *machine = MACHINE(qdev_get_machine()); | |
524d18d8 DH |
496 | ObjectClass *oc; |
497 | ||
498 | g_assert(machine->possible_cpus->cpus[0].cpu); | |
499 | oc = OBJECT_CLASS(CPU_GET_CLASS(machine->possible_cpus->cpus[0].cpu)); | |
a006b67f | 500 | |
524d18d8 | 501 | s390x_new_cpu(object_class_get_name(oc), id, errp); |
a006b67f MR |
502 | } |
503 | ||
6286b419 DH |
504 | static void s390_nmi(NMIState *n, int cpu_index, Error **errp) |
505 | { | |
506 | CPUState *cs = qemu_get_cpu(cpu_index); | |
507 | ||
0fc60ca5 | 508 | s390_cpu_restart(S390_CPU(cs)); |
6286b419 DH |
509 | } |
510 | ||
d07aa7c7 AK |
511 | static void ccw_machine_class_init(ObjectClass *oc, void *data) |
512 | { | |
513 | MachineClass *mc = MACHINE_CLASS(oc); | |
3dd7852f | 514 | NMIClass *nc = NMI_CLASS(oc); |
502edbf8 | 515 | HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); |
9700230b | 516 | S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); |
d07aa7c7 | 517 | |
9700230b | 518 | s390mc->ri_allowed = true; |
e73316d5 | 519 | s390mc->cpu_model_allowed = true; |
e996583e | 520 | s390mc->css_migration_enabled = true; |
d07aa7c7 | 521 | mc->init = ccw_init; |
db3b2566 | 522 | mc->reset = s390_machine_reset; |
a006b67f | 523 | mc->hot_add_cpu = s390_hot_add_cpu; |
d07aa7c7 AK |
524 | mc->block_default_type = IF_VIRTIO; |
525 | mc->no_cdrom = 1; | |
526 | mc->no_floppy = 1; | |
d07aa7c7 AK |
527 | mc->no_parallel = 1; |
528 | mc->no_sdcard = 1; | |
f42dc44a | 529 | mc->max_cpus = S390_MAX_CPUS; |
4dc3b151 | 530 | mc->has_hotpluggable_cpus = true; |
debbdc00 | 531 | assert(!mc->get_hotplug_handler); |
502edbf8 | 532 | mc->get_hotplug_handler = s390_get_hotplug_handler; |
4dc3b151 DH |
533 | mc->cpu_index_to_instance_props = s390_cpu_index_to_props; |
534 | mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids; | |
b6805e12 IM |
535 | /* it is overridden with 'host' cpu *in kvm_arch_init* */ |
536 | mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu"); | |
502edbf8 | 537 | hc->plug = s390_machine_device_plug; |
f2f3beb0 | 538 | hc->unplug_request = s390_machine_device_unplug_request; |
3dd7852f | 539 | nc->nmi_monitor_handler = s390_nmi; |
d07aa7c7 AK |
540 | } |
541 | ||
2eb1cd07 TK |
542 | static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp) |
543 | { | |
544 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
545 | ||
546 | return ms->aes_key_wrap; | |
547 | } | |
548 | ||
549 | static inline void machine_set_aes_key_wrap(Object *obj, bool value, | |
550 | Error **errp) | |
551 | { | |
552 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
553 | ||
554 | ms->aes_key_wrap = value; | |
555 | } | |
556 | ||
557 | static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp) | |
558 | { | |
559 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
560 | ||
561 | return ms->dea_key_wrap; | |
562 | } | |
563 | ||
564 | static inline void machine_set_dea_key_wrap(Object *obj, bool value, | |
565 | Error **errp) | |
566 | { | |
567 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
568 | ||
569 | ms->dea_key_wrap = value; | |
570 | } | |
571 | ||
cec8bbf7 | 572 | static S390CcwMachineClass *current_mc; |
9700230b | 573 | |
cec8bbf7 HP |
574 | static S390CcwMachineClass *get_machine_class(void) |
575 | { | |
576 | if (unlikely(!current_mc)) { | |
392529cb | 577 | /* |
cec8bbf7 HP |
578 | * No s390 ccw machine was instantiated, we are likely to |
579 | * be called for the 'none' machine. The properties will | |
580 | * have their after-initialization values. | |
581 | */ | |
582 | current_mc = S390_MACHINE_CLASS( | |
583 | object_class_by_name(TYPE_S390_CCW_MACHINE)); | |
9700230b | 584 | } |
cec8bbf7 | 585 | return current_mc; |
9700230b FZ |
586 | } |
587 | ||
cec8bbf7 | 588 | bool ri_allowed(void) |
e73316d5 | 589 | { |
cec8bbf7 HP |
590 | /* for "none" machine this results in true */ |
591 | return get_machine_class()->ri_allowed; | |
592 | } | |
593 | ||
594 | bool cpu_model_allowed(void) | |
595 | { | |
596 | /* for "none" machine this results in true */ | |
597 | return get_machine_class()->cpu_model_allowed; | |
e73316d5 CB |
598 | } |
599 | ||
7104bae9 FA |
600 | static char *machine_get_loadparm(Object *obj, Error **errp) |
601 | { | |
602 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
603 | ||
604 | return g_memdup(ms->loadparm, sizeof(ms->loadparm)); | |
605 | } | |
606 | ||
607 | static void machine_set_loadparm(Object *obj, const char *val, Error **errp) | |
608 | { | |
609 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
610 | int i; | |
611 | ||
612 | for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) { | |
95a5befc | 613 | uint8_t c = qemu_toupper(val[i]); /* mimic HMC */ |
7104bae9 FA |
614 | |
615 | if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') || | |
616 | (c == ' ')) { | |
617 | ms->loadparm[i] = c; | |
618 | } else { | |
619 | error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)", | |
620 | c, c); | |
621 | return; | |
622 | } | |
623 | } | |
624 | ||
625 | for (; i < sizeof(ms->loadparm); i++) { | |
626 | ms->loadparm[i] = ' '; /* pad right with spaces */ | |
627 | } | |
628 | } | |
274250c3 XFR |
629 | static inline bool machine_get_squash_mcss(Object *obj, Error **errp) |
630 | { | |
631 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
632 | ||
633 | return ms->s390_squash_mcss; | |
634 | } | |
635 | ||
636 | static inline void machine_set_squash_mcss(Object *obj, bool value, | |
637 | Error **errp) | |
638 | { | |
639 | S390CcwMachineState *ms = S390_CCW_MACHINE(obj); | |
640 | ||
641 | ms->s390_squash_mcss = value; | |
642 | } | |
7104bae9 | 643 | |
2eb1cd07 TK |
644 | static inline void s390_machine_initfn(Object *obj) |
645 | { | |
646 | object_property_add_bool(obj, "aes-key-wrap", | |
647 | machine_get_aes_key_wrap, | |
648 | machine_set_aes_key_wrap, NULL); | |
649 | object_property_set_description(obj, "aes-key-wrap", | |
650 | "enable/disable AES key wrapping using the CPACF wrapping key", | |
651 | NULL); | |
652 | object_property_set_bool(obj, true, "aes-key-wrap", NULL); | |
653 | ||
654 | object_property_add_bool(obj, "dea-key-wrap", | |
655 | machine_get_dea_key_wrap, | |
656 | machine_set_dea_key_wrap, NULL); | |
657 | object_property_set_description(obj, "dea-key-wrap", | |
658 | "enable/disable DEA key wrapping using the CPACF wrapping key", | |
659 | NULL); | |
660 | object_property_set_bool(obj, true, "dea-key-wrap", NULL); | |
7104bae9 FA |
661 | object_property_add_str(obj, "loadparm", |
662 | machine_get_loadparm, machine_set_loadparm, NULL); | |
663 | object_property_set_description(obj, "loadparm", | |
664 | "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted" | |
665 | " to upper case) to pass to machine loader, boot manager," | |
666 | " and guest kernel", | |
667 | NULL); | |
274250c3 XFR |
668 | object_property_add_bool(obj, "s390-squash-mcss", |
669 | machine_get_squash_mcss, | |
670 | machine_set_squash_mcss, NULL); | |
d69969e5 | 671 | object_property_set_description(obj, "s390-squash-mcss", "(deprecated) " |
274250c3 XFR |
672 | "enable/disable squashing subchannels into the default css", |
673 | NULL); | |
674 | object_property_set_bool(obj, false, "s390-squash-mcss", NULL); | |
2eb1cd07 TK |
675 | } |
676 | ||
d07aa7c7 AK |
677 | static const TypeInfo ccw_machine_info = { |
678 | .name = TYPE_S390_CCW_MACHINE, | |
679 | .parent = TYPE_MACHINE, | |
c4d3c0a2 | 680 | .abstract = true, |
2eb1cd07 TK |
681 | .instance_size = sizeof(S390CcwMachineState), |
682 | .instance_init = s390_machine_initfn, | |
9700230b | 683 | .class_size = sizeof(S390CcwMachineClass), |
d07aa7c7 | 684 | .class_init = ccw_machine_class_init, |
3dd7852f AK |
685 | .interfaces = (InterfaceInfo[]) { |
686 | { TYPE_NMI }, | |
502edbf8 | 687 | { TYPE_HOTPLUG_HANDLER}, |
3dd7852f AK |
688 | { } |
689 | }, | |
a5c95808 CH |
690 | }; |
691 | ||
52629b3b HP |
692 | bool css_migration_enabled(void) |
693 | { | |
694 | return get_machine_class()->css_migration_enabled; | |
695 | } | |
696 | ||
4fca6548 JF |
697 | #define DEFINE_CCW_MACHINE(suffix, verstr, latest) \ |
698 | static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \ | |
699 | void *data) \ | |
700 | { \ | |
701 | MachineClass *mc = MACHINE_CLASS(oc); \ | |
702 | ccw_machine_##suffix##_class_options(mc); \ | |
703 | mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ | |
704 | if (latest) { \ | |
705 | mc->alias = "s390-ccw-virtio"; \ | |
706 | mc->is_default = 1; \ | |
707 | } \ | |
708 | } \ | |
709 | static void ccw_machine_##suffix##_instance_init(Object *obj) \ | |
710 | { \ | |
711 | MachineState *machine = MACHINE(obj); \ | |
cec8bbf7 | 712 | current_mc = S390_MACHINE_CLASS(MACHINE_GET_CLASS(machine)); \ |
4fca6548 JF |
713 | ccw_machine_##suffix##_instance_options(machine); \ |
714 | } \ | |
715 | static const TypeInfo ccw_machine_##suffix##_info = { \ | |
716 | .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \ | |
717 | .parent = TYPE_S390_CCW_MACHINE, \ | |
718 | .class_init = ccw_machine_##suffix##_class_init, \ | |
719 | .instance_init = ccw_machine_##suffix##_instance_init, \ | |
720 | }; \ | |
721 | static void ccw_machine_register_##suffix(void) \ | |
722 | { \ | |
723 | type_register_static(&ccw_machine_##suffix##_info); \ | |
724 | } \ | |
0e6aac87 | 725 | type_init(ccw_machine_register_##suffix) |
4fca6548 | 726 | |
7a9cb3ad CH |
727 | #define CCW_COMPAT_2_12 \ |
728 | HW_COMPAT_2_12 | |
729 | ||
67ee0cef | 730 | #define CCW_COMPAT_2_11 \ |
bc61c8c6 CI |
731 | HW_COMPAT_2_11 \ |
732 | {\ | |
733 | .driver = TYPE_SCLP_EVENT_FACILITY,\ | |
734 | .property = "allow_all_mask_sizes",\ | |
735 | .value = "off",\ | |
736 | }, | |
67ee0cef | 737 | |
70d8d9a0 CH |
738 | #define CCW_COMPAT_2_10 \ |
739 | HW_COMPAT_2_10 | |
740 | ||
10890873 | 741 | #define CCW_COMPAT_2_9 \ |
903fd80b CI |
742 | HW_COMPAT_2_9 \ |
743 | {\ | |
744 | .driver = TYPE_S390_STATTRIB,\ | |
745 | .property = "migration-enabled",\ | |
746 | .value = "off",\ | |
747 | }, | |
10890873 | 748 | |
113725a6 | 749 | #define CCW_COMPAT_2_8 \ |
069097da HP |
750 | HW_COMPAT_2_8 \ |
751 | {\ | |
752 | .driver = TYPE_S390_FLIC_COMMON,\ | |
753 | .property = "adapter_routes_max_batch",\ | |
754 | .value = "64",\ | |
755 | }, | |
113725a6 | 756 | |
61823988 CH |
757 | #define CCW_COMPAT_2_7 \ |
758 | HW_COMPAT_2_7 | |
759 | ||
946e55f3 | 760 | #define CCW_COMPAT_2_6 \ |
04ca4b92 AY |
761 | HW_COMPAT_2_6 \ |
762 | {\ | |
763 | .driver = TYPE_S390_IPL,\ | |
764 | .property = "iplbext_migration",\ | |
765 | .value = "off",\ | |
2a79eb1a CH |
766 | }, {\ |
767 | .driver = TYPE_VIRTUAL_CSS_BRIDGE,\ | |
768 | .property = "css_dev_path",\ | |
769 | .value = "off",\ | |
04ca4b92 | 770 | }, |
946e55f3 | 771 | |
cf87e0a3 SL |
772 | #define CCW_COMPAT_2_5 \ |
773 | HW_COMPAT_2_5 | |
774 | ||
9ef40173 | 775 | #define CCW_COMPAT_2_4 \ |
54d8ec84 | 776 | HW_COMPAT_2_4 \ |
9ef40173 JH |
777 | {\ |
778 | .driver = TYPE_S390_SKEYS,\ | |
779 | .property = "migration-enabled",\ | |
780 | .value = "off",\ | |
542571d5 CH |
781 | },{\ |
782 | .driver = "virtio-blk-ccw",\ | |
783 | .property = "max_revision",\ | |
784 | .value = "0",\ | |
785 | },{\ | |
786 | .driver = "virtio-balloon-ccw",\ | |
787 | .property = "max_revision",\ | |
788 | .value = "0",\ | |
789 | },{\ | |
790 | .driver = "virtio-serial-ccw",\ | |
791 | .property = "max_revision",\ | |
792 | .value = "0",\ | |
793 | },{\ | |
794 | .driver = "virtio-9p-ccw",\ | |
795 | .property = "max_revision",\ | |
796 | .value = "0",\ | |
797 | },{\ | |
798 | .driver = "virtio-rng-ccw",\ | |
799 | .property = "max_revision",\ | |
800 | .value = "0",\ | |
085b0b05 CH |
801 | },{\ |
802 | .driver = "virtio-net-ccw",\ | |
803 | .property = "max_revision",\ | |
804 | .value = "0",\ | |
805 | },{\ | |
806 | .driver = "virtio-scsi-ccw",\ | |
807 | .property = "max_revision",\ | |
808 | .value = "0",\ | |
809 | },{\ | |
810 | .driver = "vhost-scsi-ccw",\ | |
811 | .property = "max_revision",\ | |
812 | .value = "0",\ | |
9ef40173 JH |
813 | }, |
814 | ||
2c5a2eef | 815 | static void ccw_machine_3_0_instance_options(MachineState *machine) |
7a9cb3ad CH |
816 | { |
817 | } | |
818 | ||
2c5a2eef | 819 | static void ccw_machine_3_0_class_options(MachineClass *mc) |
7a9cb3ad CH |
820 | { |
821 | } | |
2c5a2eef | 822 | DEFINE_CCW_MACHINE(3_0, "3.0", true); |
7a9cb3ad | 823 | |
67ee0cef CH |
824 | static void ccw_machine_2_12_instance_options(MachineState *machine) |
825 | { | |
2c5a2eef | 826 | ccw_machine_3_0_instance_options(machine); |
67ee0cef CH |
827 | } |
828 | ||
829 | static void ccw_machine_2_12_class_options(MachineClass *mc) | |
830 | { | |
2c5a2eef | 831 | ccw_machine_3_0_class_options(mc); |
7a9cb3ad | 832 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_12); |
67ee0cef | 833 | } |
7a9cb3ad | 834 | DEFINE_CCW_MACHINE(2_12, "2.12", false); |
67ee0cef | 835 | |
70d8d9a0 CH |
836 | static void ccw_machine_2_11_instance_options(MachineState *machine) |
837 | { | |
35b4df64 | 838 | static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V2_11 }; |
67ee0cef | 839 | ccw_machine_2_12_instance_options(machine); |
35b4df64 DH |
840 | |
841 | /* before 2.12 we emulated the very first z900 */ | |
842 | s390_set_qemu_cpu_model(0x2064, 7, 1, qemu_cpu_feat); | |
70d8d9a0 CH |
843 | } |
844 | ||
845 | static void ccw_machine_2_11_class_options(MachineClass *mc) | |
846 | { | |
67ee0cef CH |
847 | ccw_machine_2_12_class_options(mc); |
848 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_11); | |
70d8d9a0 | 849 | } |
67ee0cef | 850 | DEFINE_CCW_MACHINE(2_11, "2.11", false); |
70d8d9a0 | 851 | |
10890873 CH |
852 | static void ccw_machine_2_10_instance_options(MachineState *machine) |
853 | { | |
70d8d9a0 | 854 | ccw_machine_2_11_instance_options(machine); |
10890873 CH |
855 | } |
856 | ||
857 | static void ccw_machine_2_10_class_options(MachineClass *mc) | |
858 | { | |
70d8d9a0 CH |
859 | ccw_machine_2_11_class_options(mc); |
860 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_10); | |
10890873 | 861 | } |
70d8d9a0 | 862 | DEFINE_CCW_MACHINE(2_10, "2.10", false); |
10890873 | 863 | |
113725a6 CH |
864 | static void ccw_machine_2_9_instance_options(MachineState *machine) |
865 | { | |
10890873 | 866 | ccw_machine_2_10_instance_options(machine); |
7223bcce JH |
867 | s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP); |
868 | s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2); | |
3b00f702 YMZ |
869 | s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI); |
870 | s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION); | |
871 | s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION); | |
113725a6 CH |
872 | } |
873 | ||
874 | static void ccw_machine_2_9_class_options(MachineClass *mc) | |
875 | { | |
52629b3b HP |
876 | S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); |
877 | ||
10890873 CH |
878 | ccw_machine_2_10_class_options(mc); |
879 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9); | |
52629b3b | 880 | s390mc->css_migration_enabled = false; |
113725a6 | 881 | } |
10890873 | 882 | DEFINE_CCW_MACHINE(2_9, "2.9", false); |
113725a6 | 883 | |
61823988 CH |
884 | static void ccw_machine_2_8_instance_options(MachineState *machine) |
885 | { | |
113725a6 | 886 | ccw_machine_2_9_instance_options(machine); |
61823988 CH |
887 | } |
888 | ||
889 | static void ccw_machine_2_8_class_options(MachineClass *mc) | |
890 | { | |
113725a6 CH |
891 | ccw_machine_2_9_class_options(mc); |
892 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_8); | |
61823988 | 893 | } |
113725a6 | 894 | DEFINE_CCW_MACHINE(2_8, "2.8", false); |
61823988 | 895 | |
946e55f3 CH |
896 | static void ccw_machine_2_7_instance_options(MachineState *machine) |
897 | { | |
61823988 | 898 | ccw_machine_2_8_instance_options(machine); |
946e55f3 CH |
899 | } |
900 | ||
901 | static void ccw_machine_2_7_class_options(MachineClass *mc) | |
902 | { | |
e73316d5 CB |
903 | S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); |
904 | ||
905 | s390mc->cpu_model_allowed = false; | |
61823988 CH |
906 | ccw_machine_2_8_class_options(mc); |
907 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7); | |
946e55f3 | 908 | } |
61823988 | 909 | DEFINE_CCW_MACHINE(2_7, "2.7", false); |
946e55f3 | 910 | |
4fca6548 | 911 | static void ccw_machine_2_6_instance_options(MachineState *machine) |
c4d3c0a2 | 912 | { |
946e55f3 | 913 | ccw_machine_2_7_instance_options(machine); |
c4d3c0a2 CB |
914 | } |
915 | ||
4fca6548 | 916 | static void ccw_machine_2_6_class_options(MachineClass *mc) |
84b48ad6 | 917 | { |
9700230b FZ |
918 | S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); |
919 | ||
920 | s390mc->ri_allowed = false; | |
946e55f3 CH |
921 | ccw_machine_2_7_class_options(mc); |
922 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6); | |
84b48ad6 | 923 | } |
946e55f3 | 924 | DEFINE_CCW_MACHINE(2_6, "2.6", false); |
84b48ad6 | 925 | |
4fca6548 JF |
926 | static void ccw_machine_2_5_instance_options(MachineState *machine) |
927 | { | |
946e55f3 | 928 | ccw_machine_2_6_instance_options(machine); |
4fca6548 | 929 | } |
84b48ad6 | 930 | |
4fca6548 | 931 | static void ccw_machine_2_5_class_options(MachineClass *mc) |
b21b7598 | 932 | { |
946e55f3 | 933 | ccw_machine_2_6_class_options(mc); |
4fca6548 JF |
934 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5); |
935 | } | |
936 | DEFINE_CCW_MACHINE(2_5, "2.5", false); | |
b21b7598 | 937 | |
4fca6548 JF |
938 | static void ccw_machine_2_4_instance_options(MachineState *machine) |
939 | { | |
940 | ccw_machine_2_5_instance_options(machine); | |
b21b7598 CH |
941 | } |
942 | ||
4fca6548 JF |
943 | static void ccw_machine_2_4_class_options(MachineClass *mc) |
944 | { | |
946e55f3 | 945 | ccw_machine_2_5_class_options(mc); |
4fca6548 JF |
946 | SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4); |
947 | } | |
948 | DEFINE_CCW_MACHINE(2_4, "2.4", false); | |
b21b7598 | 949 | |
d07aa7c7 | 950 | static void ccw_machine_register_types(void) |
a5c95808 | 951 | { |
d07aa7c7 | 952 | type_register_static(&ccw_machine_info); |
a5c95808 CH |
953 | } |
954 | ||
d07aa7c7 | 955 | type_init(ccw_machine_register_types) |