1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "qemu/osdep.h"
27#include "qapi/error.h"
28#include "cpu.h"
29#include "internal.h"
30#include "kvm_s390x.h"
31#include "sysemu/kvm.h"
32#include "qemu-common.h"
33#include "qemu/cutils.h"
34#include "qemu/timer.h"
35#include "qemu/error-report.h"
36#include "trace.h"
37#include "qapi/visitor.h"
38#include "qapi/qapi-visit-misc.h"
39#include "qapi/qapi-visit-run-state.h"
40#include "sysemu/hw_accel.h"
41#include "exec/exec-all.h"
42#include "hw/qdev-properties.h"
43#ifndef CONFIG_USER_ONLY
44#include "hw/hw.h"
45#include "sysemu/arch_init.h"
46#include "sysemu/sysemu.h"
47#endif
48#include "fpu/softfloat.h"
49
50#define CR0_RESET 0xE0UL
51#define CR14_RESET 0xC2000000UL;
52
53static void s390_cpu_set_pc(CPUState *cs, vaddr value)
54{
55 S390CPU *cpu = S390_CPU(cs);
56
57 cpu->env.psw.addr = value;
58}
59
60static bool s390_cpu_has_work(CPUState *cs)
61{
62 S390CPU *cpu = S390_CPU(cs);
63
64
65 if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD &&
66 s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
67 return false;
68 }
69
70 if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
71 return false;
72 }
73
74 return s390_cpu_has_int(cpu);
75}
76
77#if !defined(CONFIG_USER_ONLY)
78
79static void s390_cpu_load_normal(CPUState *s)
80{
81 S390CPU *cpu = S390_CPU(s);
82 cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR;
83 cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64;
84 s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
85}
86#endif
87
88
89static void s390_cpu_reset(CPUState *s)
90{
91 S390CPU *cpu = S390_CPU(s);
92 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
93 CPUS390XState *env = &cpu->env;
94
95 env->pfault_token = -1UL;
96 env->bpbc = false;
97 scc->parent_reset(s);
98 cpu->env.sigp_order = 0;
99 s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
100}
101
102
103static void s390_cpu_initial_reset(CPUState *s)
104{
105 S390CPU *cpu = S390_CPU(s);
106 CPUS390XState *env = &cpu->env;
107
108 s390_cpu_reset(s);
109
110 memset(&env->start_initial_reset_fields, 0,
111 offsetof(CPUS390XState, end_reset_fields) -
112 offsetof(CPUS390XState, start_initial_reset_fields));
113
114
115 env->cregs[0] = CR0_RESET;
116 env->cregs[14] = CR14_RESET;
117
118
119 env->gbea = 1;
120
121 env->pfault_token = -1UL;
122
123
124 set_float_detect_tininess(float_tininess_before_rounding,
125 &env->fpu_status);
126
127
128 if (kvm_enabled()) {
129 kvm_s390_reset_vcpu(cpu);
130 }
131}
132
133
134static void s390_cpu_full_reset(CPUState *s)
135{
136 S390CPU *cpu = S390_CPU(s);
137 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
138 CPUS390XState *env = &cpu->env;
139
140 scc->parent_reset(s);
141 cpu->env.sigp_order = 0;
142 s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
143
144 memset(env, 0, offsetof(CPUS390XState, end_reset_fields));
145
146
147 env->cregs[0] = CR0_RESET;
148 env->cregs[14] = CR14_RESET;
149
150
151 env->gbea = 1;
152
153 env->pfault_token = -1UL;
154
155
156 set_float_detect_tininess(float_tininess_before_rounding,
157 &env->fpu_status);
158
159
160 if (kvm_enabled()) {
161 kvm_s390_reset_vcpu(cpu);
162 }
163}
164
165#if !defined(CONFIG_USER_ONLY)
166static void s390_cpu_machine_reset_cb(void *opaque)
167{
168 S390CPU *cpu = opaque;
169
170 run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
171}
172#endif
173
174static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
175{
176 info->mach = bfd_mach_s390_64;
177 info->print_insn = print_insn_s390;
178}
179
180static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
181{
182 CPUState *cs = CPU(dev);
183 S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
184#if !defined(CONFIG_USER_ONLY)
185 S390CPU *cpu = S390_CPU(dev);
186#endif
187 Error *err = NULL;
188
189
190 s390_realize_cpu_model(cs, &err);
191 if (err) {
192 goto out;
193 }
194
195#if !defined(CONFIG_USER_ONLY)
196 if (cpu->env.core_id >= max_cpus) {
197 error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
198 ", maximum core-id: %d", cpu->env.core_id,
199 max_cpus - 1);
200 goto out;
201 }
202
203 if (cpu_exists(cpu->env.core_id)) {
204 error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
205 ", it already exists", cpu->env.core_id);
206 goto out;
207 }
208
209
210 cs->cpu_index = cpu->env.core_id;
211#endif
212
213 cpu_exec_realizefn(cs, &err);
214 if (err != NULL) {
215 goto out;
216 }
217
218#if !defined(CONFIG_USER_ONLY)
219 qemu_register_reset(s390_cpu_machine_reset_cb, cpu);
220#endif
221 s390_cpu_gdb_init(cs);
222 qemu_init_vcpu(cs);
223#if !defined(CONFIG_USER_ONLY)
224 run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
225#else
226 cpu_reset(cs);
227#endif
228
229 scc->parent_realize(dev, &err);
230out:
231 error_propagate(errp, err);
232}
233
234static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
235{
236 GuestPanicInformation *panic_info;
237 S390CPU *cpu = S390_CPU(cs);
238
239 cpu_synchronize_state(cs);
240 panic_info = g_malloc0(sizeof(GuestPanicInformation));
241
242 panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
243#if !defined(CONFIG_USER_ONLY)
244 panic_info->u.s390.core = cpu->env.core_id;
245#else
246 panic_info->u.s390.core = 0;
247#endif
248 panic_info->u.s390.psw_mask = cpu->env.psw.mask;
249 panic_info->u.s390.psw_addr = cpu->env.psw.addr;
250 panic_info->u.s390.reason = cpu->env.crash_reason;
251
252 return panic_info;
253}
254
255static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
256 const char *name, void *opaque,
257 Error **errp)
258{
259 CPUState *cs = CPU(obj);
260 GuestPanicInformation *panic_info;
261
262 if (!cs->crash_occurred) {
263 error_setg(errp, "No crash occurred");
264 return;
265 }
266
267 panic_info = s390_cpu_get_crash_info(cs);
268
269 visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
270 errp);
271 qapi_free_GuestPanicInformation(panic_info);
272}
273
274static void s390_cpu_initfn(Object *obj)
275{
276 CPUState *cs = CPU(obj);
277 S390CPU *cpu = S390_CPU(obj);
278 CPUS390XState *env = &cpu->env;
279#if !defined(CONFIG_USER_ONLY)
280 struct tm tm;
281#endif
282
283 cs->env_ptr = env;
284 cs->halted = 1;
285 cs->exception_index = EXCP_HLT;
286 object_property_add(obj, "crash-information", "GuestPanicInformation",
287 s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL);
288 s390_cpu_model_register_props(obj);
289#if !defined(CONFIG_USER_ONLY)
290 qemu_get_timedate(&tm, 0);
291 env->tod_offset = TOD_UNIX_EPOCH +
292 (time2tod(mktimegm(&tm)) * 1000000000ULL);
293 env->tod_basetime = 0;
294 env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
295 env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
296 s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
297#endif
298}
299
300static void s390_cpu_finalize(Object *obj)
301{
302#if !defined(CONFIG_USER_ONLY)
303 S390CPU *cpu = S390_CPU(obj);
304
305 qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
306 g_free(cpu->irqstate);
307#endif
308}
309
310#if !defined(CONFIG_USER_ONLY)
311static bool disabled_wait(CPUState *cpu)
312{
313 return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
314 (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
315}
316
317static unsigned s390_count_running_cpus(void)
318{
319 CPUState *cpu;
320 int nr_running = 0;
321
322 CPU_FOREACH(cpu) {
323 uint8_t state = S390_CPU(cpu)->env.cpu_state;
324 if (state == S390_CPU_STATE_OPERATING ||
325 state == S390_CPU_STATE_LOAD) {
326 if (!disabled_wait(cpu)) {
327 nr_running++;
328 }
329 }
330 }
331
332 return nr_running;
333}
334
335unsigned int s390_cpu_halt(S390CPU *cpu)
336{
337 CPUState *cs = CPU(cpu);
338 trace_cpu_halt(cs->cpu_index);
339
340 if (!cs->halted) {
341 cs->halted = 1;
342 cs->exception_index = EXCP_HLT;
343 }
344
345 return s390_count_running_cpus();
346}
347
348void s390_cpu_unhalt(S390CPU *cpu)
349{
350 CPUState *cs = CPU(cpu);
351 trace_cpu_unhalt(cs->cpu_index);
352
353 if (cs->halted) {
354 cs->halted = 0;
355 cs->exception_index = -1;
356 }
357}
358
359unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
360 {
361 trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
362
363 switch (cpu_state) {
364 case S390_CPU_STATE_STOPPED:
365 case S390_CPU_STATE_CHECK_STOP:
366
367 s390_cpu_halt(cpu);
368 break;
369 case S390_CPU_STATE_OPERATING:
370 case S390_CPU_STATE_LOAD:
371
372
373
374
375
376
377 if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
378 s390_cpu_unhalt(cpu);
379 }
380 break;
381 default:
382 error_report("Requested CPU state is not a valid S390 CPU state: %u",
383 cpu_state);
384 exit(1);
385 }
386 if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
387 kvm_s390_set_cpu_state(cpu, cpu_state);
388 }
389 cpu->env.cpu_state = cpu_state;
390
391 return s390_count_running_cpus();
392}
393
394int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
395{
396 int r = 0;
397
398 if (kvm_enabled()) {
399 r = kvm_s390_get_clock_ext(tod_high, tod_low);
400 if (r == -ENXIO) {
401 return kvm_s390_get_clock(tod_high, tod_low);
402 }
403 } else {
404
405 *tod_high = 0;
406 *tod_low = 0;
407 }
408
409 return r;
410}
411
412int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
413{
414 int r = 0;
415
416 if (kvm_enabled()) {
417 r = kvm_s390_set_clock_ext(tod_high, tod_low);
418 if (r == -ENXIO) {
419 return kvm_s390_set_clock(tod_high, tod_low);
420 }
421 }
422
423 return r;
424}
425
426int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
427{
428 if (kvm_enabled()) {
429 return kvm_s390_set_mem_limit(new_limit, hw_limit);
430 }
431 return 0;
432}
433
434void s390_cmma_reset(void)
435{
436 if (kvm_enabled()) {
437 kvm_s390_cmma_reset();
438 }
439}
440
441int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
442 int vq, bool assign)
443{
444 if (kvm_enabled()) {
445 return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
446 } else {
447 return 0;
448 }
449}
450
451void s390_crypto_reset(void)
452{
453 if (kvm_enabled()) {
454 kvm_s390_crypto_reset();
455 }
456}
457
458bool s390_get_squash_mcss(void)
459{
460 if (object_property_get_bool(OBJECT(qdev_get_machine()), "s390-squash-mcss",
461 NULL)) {
462 return true;
463 }
464
465 return false;
466}
467
468void s390_enable_css_support(S390CPU *cpu)
469{
470 if (kvm_enabled()) {
471 kvm_s390_enable_css_support(cpu);
472 }
473}
474#endif
475
476static gchar *s390_gdb_arch_name(CPUState *cs)
477{
478 return g_strdup("s390:64-bit");
479}
480
481static Property s390x_cpu_properties[] = {
482#if !defined(CONFIG_USER_ONLY)
483 DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0),
484#endif
485 DEFINE_PROP_END_OF_LIST()
486};
487
488static void s390_cpu_class_init(ObjectClass *oc, void *data)
489{
490 S390CPUClass *scc = S390_CPU_CLASS(oc);
491 CPUClass *cc = CPU_CLASS(scc);
492 DeviceClass *dc = DEVICE_CLASS(oc);
493
494 device_class_set_parent_realize(dc, s390_cpu_realizefn,
495 &scc->parent_realize);
496 dc->props = s390x_cpu_properties;
497 dc->user_creatable = true;
498
499 scc->parent_reset = cc->reset;
500#if !defined(CONFIG_USER_ONLY)
501 scc->load_normal = s390_cpu_load_normal;
502#endif
503 scc->cpu_reset = s390_cpu_reset;
504 scc->initial_cpu_reset = s390_cpu_initial_reset;
505 cc->reset = s390_cpu_full_reset;
506 cc->class_by_name = s390_cpu_class_by_name,
507 cc->has_work = s390_cpu_has_work;
508#ifdef CONFIG_TCG
509 cc->do_interrupt = s390_cpu_do_interrupt;
510#endif
511 cc->dump_state = s390_cpu_dump_state;
512 cc->get_crash_info = s390_cpu_get_crash_info;
513 cc->set_pc = s390_cpu_set_pc;
514 cc->gdb_read_register = s390_cpu_gdb_read_register;
515 cc->gdb_write_register = s390_cpu_gdb_write_register;
516#ifdef CONFIG_USER_ONLY
517 cc->handle_mmu_fault = s390_cpu_handle_mmu_fault;
518#else
519 cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
520 cc->vmsd = &vmstate_s390_cpu;
521 cc->write_elf64_note = s390_cpu_write_elf64_note;
522#ifdef CONFIG_TCG
523 cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
524 cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
525 cc->do_unaligned_access = s390x_cpu_do_unaligned_access;
526#endif
527#endif
528 cc->disas_set_info = s390_cpu_disas_set_info;
529#ifdef CONFIG_TCG
530 cc->tcg_initialize = s390x_translate_init;
531#endif
532
533 cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
534 cc->gdb_core_xml_file = "s390x-core64.xml";
535 cc->gdb_arch_name = s390_gdb_arch_name;
536
537 s390_cpu_model_class_register_props(oc);
538}
539
540static const TypeInfo s390_cpu_type_info = {
541 .name = TYPE_S390_CPU,
542 .parent = TYPE_CPU,
543 .instance_size = sizeof(S390CPU),
544 .instance_init = s390_cpu_initfn,
545 .instance_finalize = s390_cpu_finalize,
546 .abstract = true,
547 .class_size = sizeof(S390CPUClass),
548 .class_init = s390_cpu_class_init,
549};
550
551static void s390_cpu_register_types(void)
552{
553 type_register_static(&s390_cpu_type_info);
554}
555
556type_init(s390_cpu_register_types)
557