1 | /* |
2 | * QEMU S/390 CPU |
3 | * |
4 | * Copyright (c) 2009 Ulrich Hecht |
5 | * Copyright (c) 2011 Alexander Graf |
6 | * Copyright (c) 2012 SUSE LINUX Products GmbH |
7 | * Copyright (c) 2012 IBM Corp. |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
21 | */ |
22 | |
23 | #include "qemu/osdep.h" |
24 | #include "qapi/error.h" |
25 | #include "cpu.h" |
26 | #include "internal.h" |
27 | #include "kvm_s390x.h" |
28 | #include "sysemu/kvm.h" |
29 | #include "sysemu/reset.h" |
30 | #include "qemu/timer.h" |
31 | #include "qemu/error-report.h" |
32 | #include "qemu/module.h" |
33 | #include "trace.h" |
34 | #include "qapi/visitor.h" |
35 | #include "qapi/qapi-types-machine.h" |
36 | #include "qapi/qapi-visit-run-state.h" |
37 | #include "sysemu/hw_accel.h" |
38 | #include "hw/qdev-properties.h" |
39 | #ifndef CONFIG_USER_ONLY |
40 | #include "hw/boards.h" |
41 | #include "sysemu/arch_init.h" |
42 | #include "sysemu/sysemu.h" |
43 | #include "sysemu/tcg.h" |
44 | #endif |
45 | #include "fpu/softfloat-helpers.h" |
46 | |
47 | #define CR0_RESET 0xE0UL |
48 | #define CR14_RESET 0xC2000000UL; |
49 | |
50 | static void s390_cpu_set_pc(CPUState *cs, vaddr value) |
51 | { |
52 | S390CPU *cpu = S390_CPU(cs); |
53 | |
54 | cpu->env.psw.addr = value; |
55 | } |
56 | |
57 | static bool s390_cpu_has_work(CPUState *cs) |
58 | { |
59 | S390CPU *cpu = S390_CPU(cs); |
60 | |
61 | /* STOPPED cpus can never wake up */ |
62 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD && |
63 | s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) { |
64 | return false; |
65 | } |
66 | |
67 | if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { |
68 | return false; |
69 | } |
70 | |
71 | return s390_cpu_has_int(cpu); |
72 | } |
73 | |
74 | #if !defined(CONFIG_USER_ONLY) |
75 | /* S390CPUClass::load_normal() */ |
76 | static void s390_cpu_load_normal(CPUState *s) |
77 | { |
78 | S390CPU *cpu = S390_CPU(s); |
79 | cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR; |
80 | cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64; |
81 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
82 | } |
83 | #endif |
84 | |
85 | /* S390CPUClass::cpu_reset() */ |
86 | static void s390_cpu_reset(CPUState *s) |
87 | { |
88 | S390CPU *cpu = S390_CPU(s); |
89 | S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); |
90 | CPUS390XState *env = &cpu->env; |
91 | |
92 | env->pfault_token = -1UL; |
93 | env->bpbc = false; |
94 | scc->parent_reset(s); |
95 | cpu->env.sigp_order = 0; |
96 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
97 | } |
98 | |
99 | /* S390CPUClass::initial_reset() */ |
100 | static void s390_cpu_initial_reset(CPUState *s) |
101 | { |
102 | S390CPU *cpu = S390_CPU(s); |
103 | CPUS390XState *env = &cpu->env; |
104 | |
105 | s390_cpu_reset(s); |
106 | /* initial reset does not clear everything! */ |
107 | memset(&env->start_initial_reset_fields, 0, |
108 | offsetof(CPUS390XState, end_reset_fields) - |
109 | offsetof(CPUS390XState, start_initial_reset_fields)); |
110 | |
111 | /* architectured initial values for CR 0 and 14 */ |
112 | env->cregs[0] = CR0_RESET; |
113 | env->cregs[14] = CR14_RESET; |
114 | |
115 | /* architectured initial value for Breaking-Event-Address register */ |
116 | env->gbea = 1; |
117 | |
118 | env->pfault_token = -1UL; |
119 | |
120 | /* tininess for underflow is detected before rounding */ |
121 | set_float_detect_tininess(float_tininess_before_rounding, |
122 | &env->fpu_status); |
123 | |
124 | /* Reset state inside the kernel that we cannot access yet from QEMU. */ |
125 | if (kvm_enabled()) { |
126 | kvm_s390_reset_vcpu(cpu); |
127 | } |
128 | } |
129 | |
130 | /* CPUClass:reset() */ |
131 | static void s390_cpu_full_reset(CPUState *s) |
132 | { |
133 | S390CPU *cpu = S390_CPU(s); |
134 | S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); |
135 | CPUS390XState *env = &cpu->env; |
136 | |
137 | scc->parent_reset(s); |
138 | cpu->env.sigp_order = 0; |
139 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
140 | |
141 | memset(env, 0, offsetof(CPUS390XState, end_reset_fields)); |
142 | |
143 | /* architectured initial values for CR 0 and 14 */ |
144 | env->cregs[0] = CR0_RESET; |
145 | env->cregs[14] = CR14_RESET; |
146 | |
147 | #if defined(CONFIG_USER_ONLY) |
148 | /* user mode should always be allowed to use the full FPU */ |
149 | env->cregs[0] |= CR0_AFP; |
150 | if (s390_has_feat(S390_FEAT_VECTOR)) { |
151 | env->cregs[0] |= CR0_VECTOR; |
152 | } |
153 | #endif |
154 | |
155 | /* architectured initial value for Breaking-Event-Address register */ |
156 | env->gbea = 1; |
157 | |
158 | env->pfault_token = -1UL; |
159 | |
160 | /* tininess for underflow is detected before rounding */ |
161 | set_float_detect_tininess(float_tininess_before_rounding, |
162 | &env->fpu_status); |
163 | |
164 | /* Reset state inside the kernel that we cannot access yet from QEMU. */ |
165 | if (kvm_enabled()) { |
166 | kvm_s390_reset_vcpu(cpu); |
167 | } |
168 | } |
169 | |
170 | #if !defined(CONFIG_USER_ONLY) |
171 | static void s390_cpu_machine_reset_cb(void *opaque) |
172 | { |
173 | S390CPU *cpu = opaque; |
174 | |
175 | run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL); |
176 | } |
177 | #endif |
178 | |
179 | static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) |
180 | { |
181 | info->mach = bfd_mach_s390_64; |
182 | info->print_insn = print_insn_s390; |
183 | } |
184 | |
185 | static void s390_cpu_realizefn(DeviceState *dev, Error **errp) |
186 | { |
187 | CPUState *cs = CPU(dev); |
188 | S390CPUClass *scc = S390_CPU_GET_CLASS(dev); |
189 | #if !defined(CONFIG_USER_ONLY) |
190 | S390CPU *cpu = S390_CPU(dev); |
191 | #endif |
192 | Error *err = NULL; |
193 | |
194 | /* the model has to be realized before qemu_init_vcpu() due to kvm */ |
195 | s390_realize_cpu_model(cs, &err); |
196 | if (err) { |
197 | goto out; |
198 | } |
199 | |
200 | #if !defined(CONFIG_USER_ONLY) |
201 | MachineState *ms = MACHINE(qdev_get_machine()); |
202 | unsigned int max_cpus = ms->smp.max_cpus; |
203 | if (cpu->env.core_id >= max_cpus) { |
204 | error_setg(&err, "Unable to add CPU with core-id: %" PRIu32 |
205 | ", maximum core-id: %d" , cpu->env.core_id, |
206 | max_cpus - 1); |
207 | goto out; |
208 | } |
209 | |
210 | if (cpu_exists(cpu->env.core_id)) { |
211 | error_setg(&err, "Unable to add CPU with core-id: %" PRIu32 |
212 | ", it already exists" , cpu->env.core_id); |
213 | goto out; |
214 | } |
215 | |
216 | /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */ |
217 | cs->cpu_index = cpu->env.core_id; |
218 | #endif |
219 | |
220 | cpu_exec_realizefn(cs, &err); |
221 | if (err != NULL) { |
222 | goto out; |
223 | } |
224 | |
225 | #if !defined(CONFIG_USER_ONLY) |
226 | qemu_register_reset(s390_cpu_machine_reset_cb, cpu); |
227 | #endif |
228 | s390_cpu_gdb_init(cs); |
229 | qemu_init_vcpu(cs); |
230 | |
231 | /* |
232 | * KVM requires the initial CPU reset ioctl to be executed on the target |
233 | * CPU thread. CPU hotplug under single-threaded TCG will not work with |
234 | * run_on_cpu(), as run_on_cpu() will not work properly if called while |
235 | * the main thread is already running but the CPU hasn't been realized. |
236 | */ |
237 | if (kvm_enabled()) { |
238 | run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); |
239 | } else { |
240 | cpu_reset(cs); |
241 | } |
242 | |
243 | scc->parent_realize(dev, &err); |
244 | out: |
245 | error_propagate(errp, err); |
246 | } |
247 | |
248 | static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs) |
249 | { |
250 | GuestPanicInformation *panic_info; |
251 | S390CPU *cpu = S390_CPU(cs); |
252 | |
253 | cpu_synchronize_state(cs); |
254 | panic_info = g_malloc0(sizeof(GuestPanicInformation)); |
255 | |
256 | panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390; |
257 | #if !defined(CONFIG_USER_ONLY) |
258 | panic_info->u.s390.core = cpu->env.core_id; |
259 | #else |
260 | panic_info->u.s390.core = 0; /* sane default for non system emulation */ |
261 | #endif |
262 | panic_info->u.s390.psw_mask = cpu->env.psw.mask; |
263 | panic_info->u.s390.psw_addr = cpu->env.psw.addr; |
264 | panic_info->u.s390.reason = cpu->env.crash_reason; |
265 | |
266 | return panic_info; |
267 | } |
268 | |
269 | static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v, |
270 | const char *name, void *opaque, |
271 | Error **errp) |
272 | { |
273 | CPUState *cs = CPU(obj); |
274 | GuestPanicInformation *panic_info; |
275 | |
276 | if (!cs->crash_occurred) { |
277 | error_setg(errp, "No crash occurred" ); |
278 | return; |
279 | } |
280 | |
281 | panic_info = s390_cpu_get_crash_info(cs); |
282 | |
283 | visit_type_GuestPanicInformation(v, "crash-information" , &panic_info, |
284 | errp); |
285 | qapi_free_GuestPanicInformation(panic_info); |
286 | } |
287 | |
288 | static void s390_cpu_initfn(Object *obj) |
289 | { |
290 | CPUState *cs = CPU(obj); |
291 | S390CPU *cpu = S390_CPU(obj); |
292 | |
293 | cpu_set_cpustate_pointers(cpu); |
294 | cs->halted = 1; |
295 | cs->exception_index = EXCP_HLT; |
296 | object_property_add(obj, "crash-information" , "GuestPanicInformation" , |
297 | s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); |
298 | s390_cpu_model_register_props(obj); |
299 | #if !defined(CONFIG_USER_ONLY) |
300 | cpu->env.tod_timer = |
301 | timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); |
302 | cpu->env.cpu_timer = |
303 | timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); |
304 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
305 | #endif |
306 | } |
307 | |
308 | static void s390_cpu_finalize(Object *obj) |
309 | { |
310 | #if !defined(CONFIG_USER_ONLY) |
311 | S390CPU *cpu = S390_CPU(obj); |
312 | |
313 | qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu); |
314 | g_free(cpu->irqstate); |
315 | #endif |
316 | } |
317 | |
318 | #if !defined(CONFIG_USER_ONLY) |
319 | static bool disabled_wait(CPUState *cpu) |
320 | { |
321 | return cpu->halted && !(S390_CPU(cpu)->env.psw.mask & |
322 | (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK)); |
323 | } |
324 | |
325 | static unsigned s390_count_running_cpus(void) |
326 | { |
327 | CPUState *cpu; |
328 | int nr_running = 0; |
329 | |
330 | CPU_FOREACH(cpu) { |
331 | uint8_t state = S390_CPU(cpu)->env.cpu_state; |
332 | if (state == S390_CPU_STATE_OPERATING || |
333 | state == S390_CPU_STATE_LOAD) { |
334 | if (!disabled_wait(cpu)) { |
335 | nr_running++; |
336 | } |
337 | } |
338 | } |
339 | |
340 | return nr_running; |
341 | } |
342 | |
343 | unsigned int s390_cpu_halt(S390CPU *cpu) |
344 | { |
345 | CPUState *cs = CPU(cpu); |
346 | trace_cpu_halt(cs->cpu_index); |
347 | |
348 | if (!cs->halted) { |
349 | cs->halted = 1; |
350 | cs->exception_index = EXCP_HLT; |
351 | } |
352 | |
353 | return s390_count_running_cpus(); |
354 | } |
355 | |
356 | void s390_cpu_unhalt(S390CPU *cpu) |
357 | { |
358 | CPUState *cs = CPU(cpu); |
359 | trace_cpu_unhalt(cs->cpu_index); |
360 | |
361 | if (cs->halted) { |
362 | cs->halted = 0; |
363 | cs->exception_index = -1; |
364 | } |
365 | } |
366 | |
367 | unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) |
368 | { |
369 | trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state); |
370 | |
371 | switch (cpu_state) { |
372 | case S390_CPU_STATE_STOPPED: |
373 | case S390_CPU_STATE_CHECK_STOP: |
374 | /* halt the cpu for common infrastructure */ |
375 | s390_cpu_halt(cpu); |
376 | break; |
377 | case S390_CPU_STATE_OPERATING: |
378 | case S390_CPU_STATE_LOAD: |
379 | /* |
380 | * Starting a CPU with a PSW WAIT bit set: |
381 | * KVM: handles this internally and triggers another WAIT exit. |
382 | * TCG: will actually try to continue to run. Don't unhalt, will |
383 | * be done when the CPU actually has work (an interrupt). |
384 | */ |
385 | if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) { |
386 | s390_cpu_unhalt(cpu); |
387 | } |
388 | break; |
389 | default: |
390 | error_report("Requested CPU state is not a valid S390 CPU state: %u" , |
391 | cpu_state); |
392 | exit(1); |
393 | } |
394 | if (kvm_enabled() && cpu->env.cpu_state != cpu_state) { |
395 | kvm_s390_set_cpu_state(cpu, cpu_state); |
396 | } |
397 | cpu->env.cpu_state = cpu_state; |
398 | |
399 | return s390_count_running_cpus(); |
400 | } |
401 | |
402 | int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) |
403 | { |
404 | if (kvm_enabled()) { |
405 | return kvm_s390_set_mem_limit(new_limit, hw_limit); |
406 | } |
407 | return 0; |
408 | } |
409 | |
410 | void s390_set_max_pagesize(uint64_t pagesize, Error **errp) |
411 | { |
412 | if (kvm_enabled()) { |
413 | kvm_s390_set_max_pagesize(pagesize, errp); |
414 | } |
415 | } |
416 | |
417 | void s390_cmma_reset(void) |
418 | { |
419 | if (kvm_enabled()) { |
420 | kvm_s390_cmma_reset(); |
421 | } |
422 | } |
423 | |
424 | int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id, |
425 | int vq, bool assign) |
426 | { |
427 | if (kvm_enabled()) { |
428 | return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign); |
429 | } else { |
430 | return 0; |
431 | } |
432 | } |
433 | |
434 | void s390_crypto_reset(void) |
435 | { |
436 | if (kvm_enabled()) { |
437 | kvm_s390_crypto_reset(); |
438 | } |
439 | } |
440 | |
441 | void s390_enable_css_support(S390CPU *cpu) |
442 | { |
443 | if (kvm_enabled()) { |
444 | kvm_s390_enable_css_support(cpu); |
445 | } |
446 | } |
447 | #endif |
448 | |
449 | static gchar *s390_gdb_arch_name(CPUState *cs) |
450 | { |
451 | return g_strdup("s390:64-bit" ); |
452 | } |
453 | |
454 | static Property s390x_cpu_properties[] = { |
455 | #if !defined(CONFIG_USER_ONLY) |
456 | DEFINE_PROP_UINT32("core-id" , S390CPU, env.core_id, 0), |
457 | #endif |
458 | DEFINE_PROP_END_OF_LIST() |
459 | }; |
460 | |
461 | static void s390_cpu_class_init(ObjectClass *oc, void *data) |
462 | { |
463 | S390CPUClass *scc = S390_CPU_CLASS(oc); |
464 | CPUClass *cc = CPU_CLASS(scc); |
465 | DeviceClass *dc = DEVICE_CLASS(oc); |
466 | |
467 | device_class_set_parent_realize(dc, s390_cpu_realizefn, |
468 | &scc->parent_realize); |
469 | dc->props = s390x_cpu_properties; |
470 | dc->user_creatable = true; |
471 | |
472 | scc->parent_reset = cc->reset; |
473 | #if !defined(CONFIG_USER_ONLY) |
474 | scc->load_normal = s390_cpu_load_normal; |
475 | #endif |
476 | scc->cpu_reset = s390_cpu_reset; |
477 | scc->initial_cpu_reset = s390_cpu_initial_reset; |
478 | cc->reset = s390_cpu_full_reset; |
479 | cc->class_by_name = s390_cpu_class_by_name, |
480 | cc->has_work = s390_cpu_has_work; |
481 | #ifdef CONFIG_TCG |
482 | cc->do_interrupt = s390_cpu_do_interrupt; |
483 | #endif |
484 | cc->dump_state = s390_cpu_dump_state; |
485 | cc->get_crash_info = s390_cpu_get_crash_info; |
486 | cc->set_pc = s390_cpu_set_pc; |
487 | cc->gdb_read_register = s390_cpu_gdb_read_register; |
488 | cc->gdb_write_register = s390_cpu_gdb_write_register; |
489 | #ifndef CONFIG_USER_ONLY |
490 | cc->get_phys_page_debug = s390_cpu_get_phys_page_debug; |
491 | cc->vmsd = &vmstate_s390_cpu; |
492 | cc->write_elf64_note = s390_cpu_write_elf64_note; |
493 | #ifdef CONFIG_TCG |
494 | cc->cpu_exec_interrupt = s390_cpu_exec_interrupt; |
495 | cc->debug_excp_handler = s390x_cpu_debug_excp_handler; |
496 | cc->do_unaligned_access = s390x_cpu_do_unaligned_access; |
497 | #endif |
498 | #endif |
499 | cc->disas_set_info = s390_cpu_disas_set_info; |
500 | #ifdef CONFIG_TCG |
501 | cc->tcg_initialize = s390x_translate_init; |
502 | cc->tlb_fill = s390_cpu_tlb_fill; |
503 | #endif |
504 | |
505 | cc->gdb_num_core_regs = S390_NUM_CORE_REGS; |
506 | cc->gdb_core_xml_file = "s390x-core64.xml" ; |
507 | cc->gdb_arch_name = s390_gdb_arch_name; |
508 | |
509 | s390_cpu_model_class_register_props(oc); |
510 | } |
511 | |
512 | static const TypeInfo s390_cpu_type_info = { |
513 | .name = TYPE_S390_CPU, |
514 | .parent = TYPE_CPU, |
515 | .instance_size = sizeof(S390CPU), |
516 | .instance_init = s390_cpu_initfn, |
517 | .instance_finalize = s390_cpu_finalize, |
518 | .abstract = true, |
519 | .class_size = sizeof(S390CPUClass), |
520 | .class_init = s390_cpu_class_init, |
521 | }; |
522 | |
523 | static void s390_cpu_register_types(void) |
524 | { |
525 | type_register_static(&s390_cpu_type_info); |
526 | } |
527 | |
528 | type_init(s390_cpu_register_types) |
529 | |