1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 "qemu-common.h"
30#include "qemu/timer.h"
31#include "qemu/error-report.h"
32#include "trace.h"
33#include "qapi/visitor.h"
34#include "qapi/qapi-visit-misc.h"
35#include "qapi/qapi-visit-run-state.h"
36#include "sysemu/hw_accel.h"
37#include "hw/qdev-properties.h"
38#ifndef CONFIG_USER_ONLY
39#include "hw/hw.h"
40#include "sysemu/arch_init.h"
41#include "sysemu/sysemu.h"
42#endif
43#include "fpu/softfloat.h"
44
45#define CR0_RESET 0xE0UL
46#define CR14_RESET 0xC2000000UL;
47
48static void s390_cpu_set_pc(CPUState *cs, vaddr value)
49{
50 S390CPU *cpu = S390_CPU(cs);
51
52 cpu->env.psw.addr = value;
53}
54
55static bool s390_cpu_has_work(CPUState *cs)
56{
57 S390CPU *cpu = S390_CPU(cs);
58
59
60 if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD &&
61 s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
62 return false;
63 }
64
65 if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
66 return false;
67 }
68
69 return s390_cpu_has_int(cpu);
70}
71
72#if !defined(CONFIG_USER_ONLY)
73
74static void s390_cpu_load_normal(CPUState *s)
75{
76 S390CPU *cpu = S390_CPU(s);
77 cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR;
78 cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64;
79 s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
80}
81#endif
82
83
84static void s390_cpu_reset(CPUState *s)
85{
86 S390CPU *cpu = S390_CPU(s);
87 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
88 CPUS390XState *env = &cpu->env;
89
90 env->pfault_token = -1UL;
91 env->bpbc = false;
92 scc->parent_reset(s);
93 cpu->env.sigp_order = 0;
94 s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
95}
96
97
98static void s390_cpu_initial_reset(CPUState *s)
99{
100 S390CPU *cpu = S390_CPU(s);
101 CPUS390XState *env = &cpu->env;
102
103 s390_cpu_reset(s);
104
105 memset(&env->start_initial_reset_fields, 0,
106 offsetof(CPUS390XState, end_reset_fields) -
107 offsetof(CPUS390XState, start_initial_reset_fields));
108
109
110 env->cregs[0] = CR0_RESET;
111 env->cregs[14] = CR14_RESET;
112
113
114 env->gbea = 1;
115
116 env->pfault_token = -1UL;
117
118
119 set_float_detect_tininess(float_tininess_before_rounding,
120 &env->fpu_status);
121
122
123 if (kvm_enabled()) {
124 kvm_s390_reset_vcpu(cpu);
125 }
126}
127
128
129static void s390_cpu_full_reset(CPUState *s)
130{
131 S390CPU *cpu = S390_CPU(s);
132 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
133 CPUS390XState *env = &cpu->env;
134
135 scc->parent_reset(s);
136 cpu->env.sigp_order = 0;
137 s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
138
139 memset(env, 0, offsetof(CPUS390XState, end_reset_fields));
140
141
142 env->cregs[0] = CR0_RESET;
143 env->cregs[14] = CR14_RESET;
144
145#if defined(CONFIG_USER_ONLY)
146
147 env->cregs[0] |= CR0_AFP;
148#endif
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
224
225
226
227
228
229
230 if (kvm_enabled()) {
231 run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
232 } else {
233 cpu_reset(cs);
234 }
235
236 scc->parent_realize(dev, &err);
237out:
238 error_propagate(errp, err);
239}
240
241static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
242{
243 GuestPanicInformation *panic_info;
244 S390CPU *cpu = S390_CPU(cs);
245
246 cpu_synchronize_state(cs);
247 panic_info = g_malloc0(sizeof(GuestPanicInformation));
248
249 panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
250#if !defined(CONFIG_USER_ONLY)
251 panic_info->u.s390.core = cpu->env.core_id;
252#else
253 panic_info->u.s390.core = 0;
254#endif
255 panic_info->u.s390.psw_mask = cpu->env.psw.mask;
256 panic_info->u.s390.psw_addr = cpu->env.psw.addr;
257 panic_info->u.s390.reason = cpu->env.crash_reason;
258
259 return panic_info;
260}
261
262static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
263 const char *name, void *opaque,
264 Error **errp)
265{
266 CPUState *cs = CPU(obj);
267 GuestPanicInformation *panic_info;
268
269 if (!cs->crash_occurred) {
270 error_setg(errp, "No crash occurred");
271 return;
272 }
273
274 panic_info = s390_cpu_get_crash_info(cs);
275
276 visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
277 errp);
278 qapi_free_GuestPanicInformation(panic_info);
279}
280
281static void s390_cpu_initfn(Object *obj)
282{
283 CPUState *cs = CPU(obj);
284 S390CPU *cpu = S390_CPU(obj);
285 CPUS390XState *env = &cpu->env;
286
287 cs->env_ptr = env;
288 cs->halted = 1;
289 cs->exception_index = EXCP_HLT;
290 object_property_add(obj, "crash-information", "GuestPanicInformation",
291 s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL);
292 s390_cpu_model_register_props(obj);
293#if !defined(CONFIG_USER_ONLY)
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_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
395{
396 if (kvm_enabled()) {
397 return kvm_s390_set_mem_limit(new_limit, hw_limit);
398 }
399 return 0;
400}
401
402void s390_cmma_reset(void)
403{
404 if (kvm_enabled()) {
405 kvm_s390_cmma_reset();
406 }
407}
408
409int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
410 int vq, bool assign)
411{
412 if (kvm_enabled()) {
413 return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
414 } else {
415 return 0;
416 }
417}
418
419void s390_crypto_reset(void)
420{
421 if (kvm_enabled()) {
422 kvm_s390_crypto_reset();
423 }
424}
425
426void s390_enable_css_support(S390CPU *cpu)
427{
428 if (kvm_enabled()) {
429 kvm_s390_enable_css_support(cpu);
430 }
431}
432#endif
433
434static gchar *s390_gdb_arch_name(CPUState *cs)
435{
436 return g_strdup("s390:64-bit");
437}
438
439static Property s390x_cpu_properties[] = {
440#if !defined(CONFIG_USER_ONLY)
441 DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0),
442#endif
443 DEFINE_PROP_END_OF_LIST()
444};
445
446static void s390_cpu_class_init(ObjectClass *oc, void *data)
447{
448 S390CPUClass *scc = S390_CPU_CLASS(oc);
449 CPUClass *cc = CPU_CLASS(scc);
450 DeviceClass *dc = DEVICE_CLASS(oc);
451
452 device_class_set_parent_realize(dc, s390_cpu_realizefn,
453 &scc->parent_realize);
454 dc->props = s390x_cpu_properties;
455 dc->user_creatable = true;
456
457 scc->parent_reset = cc->reset;
458#if !defined(CONFIG_USER_ONLY)
459 scc->load_normal = s390_cpu_load_normal;
460#endif
461 scc->cpu_reset = s390_cpu_reset;
462 scc->initial_cpu_reset = s390_cpu_initial_reset;
463 cc->reset = s390_cpu_full_reset;
464 cc->class_by_name = s390_cpu_class_by_name,
465 cc->has_work = s390_cpu_has_work;
466#ifdef CONFIG_TCG
467 cc->do_interrupt = s390_cpu_do_interrupt;
468#endif
469 cc->dump_state = s390_cpu_dump_state;
470 cc->get_crash_info = s390_cpu_get_crash_info;
471 cc->set_pc = s390_cpu_set_pc;
472 cc->gdb_read_register = s390_cpu_gdb_read_register;
473 cc->gdb_write_register = s390_cpu_gdb_write_register;
474#ifdef CONFIG_USER_ONLY
475 cc->handle_mmu_fault = s390_cpu_handle_mmu_fault;
476#else
477 cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
478 cc->vmsd = &vmstate_s390_cpu;
479 cc->write_elf64_note = s390_cpu_write_elf64_note;
480#ifdef CONFIG_TCG
481 cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
482 cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
483 cc->do_unaligned_access = s390x_cpu_do_unaligned_access;
484#endif
485#endif
486 cc->disas_set_info = s390_cpu_disas_set_info;
487#ifdef CONFIG_TCG
488 cc->tcg_initialize = s390x_translate_init;
489#endif
490
491 cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
492 cc->gdb_core_xml_file = "s390x-core64.xml";
493 cc->gdb_arch_name = s390_gdb_arch_name;
494
495 s390_cpu_model_class_register_props(oc);
496}
497
498static const TypeInfo s390_cpu_type_info = {
499 .name = TYPE_S390_CPU,
500 .parent = TYPE_CPU,
501 .instance_size = sizeof(S390CPU),
502 .instance_init = s390_cpu_initfn,
503 .instance_finalize = s390_cpu_finalize,
504 .abstract = true,
505 .class_size = sizeof(S390CPUClass),
506 .class_init = s390_cpu_class_init,
507};
508
509static void s390_cpu_register_types(void)
510{
511 type_register_static(&s390_cpu_type_info);
512}
513
514type_init(s390_cpu_register_types)
515