]> git.proxmox.com Git - mirror_qemu.git/blame - target-s390x/cpu.c
exec: extract exec/tb-context.h
[mirror_qemu.git] / target-s390x / cpu.c
CommitLineData
29e4bcb2
AF
1/*
2 * QEMU S/390 CPU
3 *
1ac1a749
AF
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2011 Alexander Graf
29e4bcb2 6 * Copyright (c) 2012 SUSE LINUX Products GmbH
70bada03 7 * Copyright (c) 2012 IBM Corp.
29e4bcb2
AF
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library 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 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, see
21 * <http://www.gnu.org/licenses/lgpl-2.1.html>
70bada03
JF
22 * Contributions after 2012-12-11 are licensed under the terms of the
23 * GNU GPL, version 2 or (at your option) any later version.
29e4bcb2
AF
24 */
25
9615495a 26#include "qemu/osdep.h"
da34e65c 27#include "qapi/error.h"
564b863d 28#include "cpu.h"
29e4bcb2 29#include "qemu-common.h"
f348b6d1 30#include "qemu/cutils.h"
1de7afc9 31#include "qemu/timer.h"
eb24f7c6 32#include "qemu/error-report.h"
eb24f7c6 33#include "trace.h"
96b1a8bb 34#include "qapi/visitor.h"
741da0d3 35#include "migration/vmstate.h"
c7396bbb 36#ifndef CONFIG_USER_ONLY
741da0d3 37#include "hw/hw.h"
904e5fd5 38#include "sysemu/arch_init.h"
96b1a8bb 39#include "sysemu/sysemu.h"
a006b67f 40#include "hw/s390x/sclp.h"
904e5fd5
VM
41#endif
42
70bada03
JF
43#define CR0_RESET 0xE0UL
44#define CR14_RESET 0xC2000000UL;
45
904e5fd5
VM
46/* generate CPU information for cpu -? */
47void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf)
48{
49#ifdef CONFIG_KVM
50 (*cpu_fprintf)(f, "s390 %16s\n", "host");
51#endif
52}
29e4bcb2 53
904e5fd5
VM
54#ifndef CONFIG_USER_ONLY
55CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
56{
57 CpuDefinitionInfoList *entry;
58 CpuDefinitionInfo *info;
59
60 info = g_malloc0(sizeof(*info));
61 info->name = g_strdup("host");
62
63 entry = g_malloc0(sizeof(*entry));
64 entry->value = info;
65
66 return entry;
67}
68#endif
29e4bcb2 69
f45748f1
AF
70static void s390_cpu_set_pc(CPUState *cs, vaddr value)
71{
72 S390CPU *cpu = S390_CPU(cs);
73
74 cpu->env.psw.addr = value;
75}
76
8c2e1b00
AF
77static bool s390_cpu_has_work(CPUState *cs)
78{
79 S390CPU *cpu = S390_CPU(cs);
80 CPUS390XState *env = &cpu->env;
81
82 return (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
83 (env->psw.mask & PSW_MASK_EXT);
84}
85
29c6157c
CB
86#if !defined(CONFIG_USER_ONLY)
87/* S390CPUClass::load_normal() */
88static void s390_cpu_load_normal(CPUState *s)
89{
90 S390CPU *cpu = S390_CPU(s);
fdfba1a2 91 cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR;
29c6157c 92 cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64;
eb24f7c6 93 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
29c6157c
CB
94}
95#endif
96
f5ae2a4f 97/* S390CPUClass::cpu_reset() */
29e4bcb2
AF
98static void s390_cpu_reset(CPUState *s)
99{
100 S390CPU *cpu = S390_CPU(s);
101 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
102 CPUS390XState *env = &cpu->env;
103
819bd309 104 env->pfault_token = -1UL;
f5ae2a4f 105 scc->parent_reset(s);
18ff9494 106 cpu->env.sigp_order = 0;
eb24f7c6 107 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
00c8cb0a 108 tlb_flush(s, 1);
f5ae2a4f
CB
109}
110
111/* S390CPUClass::initial_reset() */
112static void s390_cpu_initial_reset(CPUState *s)
113{
114 S390CPU *cpu = S390_CPU(s);
115 CPUS390XState *env = &cpu->env;
cc0d079d 116 int i;
f5ae2a4f
CB
117
118 s390_cpu_reset(s);
119 /* initial reset does not touch regs,fregs and aregs */
f0c3c505 120 memset(&env->fpc, 0, offsetof(CPUS390XState, cpu_num) -
f5ae2a4f
CB
121 offsetof(CPUS390XState, fpc));
122
123 /* architectured initial values for CR 0 and 14 */
124 env->cregs[0] = CR0_RESET;
125 env->cregs[14] = CR14_RESET;
819bd309 126
3da0ab35
AJ
127 /* architectured initial value for Breaking-Event-Address register */
128 env->gbea = 1;
129
819bd309 130 env->pfault_token = -1UL;
7107e5a7 131 env->ext_index = -1;
cc0d079d
AJ
132 for (i = 0; i < ARRAY_SIZE(env->io_index); i++) {
133 env->io_index[i] = -1;
134 }
49f5c9e9 135
4a33565f
AJ
136 /* tininess for underflow is detected before rounding */
137 set_float_detect_tininess(float_tininess_before_rounding,
138 &env->fpu_status);
139
49f5c9e9
TH
140 /* Reset state inside the kernel that we cannot access yet from QEMU. */
141 if (kvm_enabled()) {
99607144 142 kvm_s390_reset_vcpu(cpu);
49f5c9e9 143 }
cbed0ba7 144 tlb_flush(s, 1);
f5ae2a4f
CB
145}
146
147/* CPUClass:reset() */
148static void s390_cpu_full_reset(CPUState *s)
149{
150 S390CPU *cpu = S390_CPU(s);
151 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
152 CPUS390XState *env = &cpu->env;
cc0d079d 153 int i;
f5ae2a4f 154
29e4bcb2 155 scc->parent_reset(s);
18ff9494 156 cpu->env.sigp_order = 0;
eb24f7c6 157 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
29e4bcb2 158
f0c3c505 159 memset(env, 0, offsetof(CPUS390XState, cpu_num));
70bada03
JF
160
161 /* architectured initial values for CR 0 and 14 */
162 env->cregs[0] = CR0_RESET;
163 env->cregs[14] = CR14_RESET;
819bd309 164
3da0ab35
AJ
165 /* architectured initial value for Breaking-Event-Address register */
166 env->gbea = 1;
167
819bd309 168 env->pfault_token = -1UL;
7107e5a7 169 env->ext_index = -1;
cc0d079d
AJ
170 for (i = 0; i < ARRAY_SIZE(env->io_index); i++) {
171 env->io_index[i] = -1;
172 }
819bd309 173
4a33565f
AJ
174 /* tininess for underflow is detected before rounding */
175 set_float_detect_tininess(float_tininess_before_rounding,
176 &env->fpu_status);
177
99607144 178 /* Reset state inside the kernel that we cannot access yet from QEMU. */
50a2c6e5
PB
179 if (kvm_enabled()) {
180 kvm_s390_reset_vcpu(cpu);
181 }
00c8cb0a 182 tlb_flush(s, 1);
29e4bcb2
AF
183}
184
70bada03
JF
185#if !defined(CONFIG_USER_ONLY)
186static void s390_cpu_machine_reset_cb(void *opaque)
187{
188 S390CPU *cpu = opaque;
189
1fad8b3b 190 run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, CPU(cpu));
70bada03
JF
191}
192#endif
193
dbad6b74
PC
194static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
195{
196 info->mach = bfd_mach_s390_64;
197 info->print_insn = print_insn_s390;
198}
199
1f136632
AF
200static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
201{
14a10fc3 202 CPUState *cs = CPU(dev);
1f136632 203 S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
c6644fc8
MR
204 S390CPU *cpu = S390_CPU(dev);
205 CPUS390XState *env = &cpu->env;
206 Error *err = NULL;
207
96b1a8bb
MR
208#if !defined(CONFIG_USER_ONLY)
209 if (cpu->id >= max_cpus) {
210 error_setg(&err, "Unable to add CPU: %" PRIi64
211 ", max allowed: %d", cpu->id, max_cpus - 1);
212 goto out;
213 }
214#endif
215 if (cpu_exists(cpu->id)) {
216 error_setg(&err, "Unable to add CPU: %" PRIi64
217 ", it already exists", cpu->id);
218 goto out;
219 }
220 if (cpu->id != scc->next_cpu_id) {
221 error_setg(&err, "Unable to add CPU: %" PRIi64
222 ", The next available id is %" PRIi64, cpu->id,
223 scc->next_cpu_id);
224 goto out;
225 }
226
c6644fc8
MR
227 cpu_exec_init(cs, &err);
228 if (err != NULL) {
96b1a8bb 229 goto out;
c6644fc8 230 }
96b1a8bb 231 scc->next_cpu_id++;
1f136632 232
c6644fc8
MR
233#if !defined(CONFIG_USER_ONLY)
234 qemu_register_reset(s390_cpu_machine_reset_cb, cpu);
235#endif
96b1a8bb 236 env->cpu_num = cpu->id;
73d510c9 237 s390_cpu_gdb_init(cs);
14a10fc3 238 qemu_init_vcpu(cs);
159855f0
DH
239#if !defined(CONFIG_USER_ONLY)
240 run_on_cpu(cs, s390_do_cpu_full_reset, cs);
241#else
14a10fc3 242 cpu_reset(cs);
159855f0 243#endif
1f136632 244
96b1a8bb
MR
245 scc->parent_realize(dev, &err);
246
a006b67f
MR
247#if !defined(CONFIG_USER_ONLY)
248 if (dev->hotplugged) {
249 raise_irq_cpu_hotplug();
250 }
251#endif
252
96b1a8bb
MR
253out:
254 error_propagate(errp, err);
255}
256
257static void s390x_cpu_get_id(Object *obj, Visitor *v, const char *name,
258 void *opaque, Error **errp)
259{
260 S390CPU *cpu = S390_CPU(obj);
261 int64_t value = cpu->id;
262
263 visit_type_int(v, name, &value, errp);
264}
265
266static void s390x_cpu_set_id(Object *obj, Visitor *v, const char *name,
267 void *opaque, Error **errp)
268{
269 S390CPU *cpu = S390_CPU(obj);
270 DeviceState *dev = DEVICE(obj);
271 const int64_t min = 0;
272 const int64_t max = UINT32_MAX;
273 Error *err = NULL;
274 int64_t value;
275
276 if (dev->realized) {
277 error_setg(errp, "Attempt to set property '%s' on '%s' after "
278 "it was realized", name, object_get_typename(obj));
279 return;
280 }
281
282 visit_type_int(v, name, &value, &err);
283 if (err) {
284 error_propagate(errp, err);
285 return;
286 }
287 if (value < min || value > max) {
288 error_setg(errp, "Property %s.%s doesn't take value %" PRId64
289 " (minimum: %" PRId64 ", maximum: %" PRId64 ")" ,
290 object_get_typename(obj), name, value, min, max);
291 return;
292 }
293 cpu->id = value;
1f136632
AF
294}
295
8f22e0df
AF
296static void s390_cpu_initfn(Object *obj)
297{
c05efcb1 298 CPUState *cs = CPU(obj);
8f22e0df
AF
299 S390CPU *cpu = S390_CPU(obj);
300 CPUS390XState *env = &cpu->env;
2b7ac767 301 static bool inited;
8f22e0df
AF
302#if !defined(CONFIG_USER_ONLY)
303 struct tm tm;
304#endif
305
c05efcb1 306 cs->env_ptr = env;
ef3027af
MR
307 cs->halted = 1;
308 cs->exception_index = EXCP_HLT;
96b1a8bb
MR
309 object_property_add(OBJECT(cpu), "id", "int64_t", s390x_cpu_get_id,
310 s390x_cpu_set_id, NULL, NULL, NULL);
8f22e0df
AF
311#if !defined(CONFIG_USER_ONLY)
312 qemu_get_timedate(&tm, 0);
313 env->tod_offset = TOD_UNIX_EPOCH +
314 (time2tod(mktimegm(&tm)) * 1000000000ULL);
315 env->tod_basetime = 0;
bc72ad67
AB
316 env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
317 env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
eb24f7c6 318 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
8f22e0df 319#endif
2b7ac767
AF
320
321 if (tcg_enabled() && !inited) {
322 inited = true;
323 s390x_translate_init();
324 }
8f22e0df
AF
325}
326
d5627ce8
AF
327static void s390_cpu_finalize(Object *obj)
328{
329#if !defined(CONFIG_USER_ONLY)
330 S390CPU *cpu = S390_CPU(obj);
331
332 qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
3cda44f7 333 g_free(cpu->irqstate);
d5627ce8
AF
334#endif
335}
336
75973bfe 337#if !defined(CONFIG_USER_ONLY)
eb24f7c6
DH
338static bool disabled_wait(CPUState *cpu)
339{
340 return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
341 (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
342}
343
75973bfe
DH
344static unsigned s390_count_running_cpus(void)
345{
346 CPUState *cpu;
347 int nr_running = 0;
348
349 CPU_FOREACH(cpu) {
350 uint8_t state = S390_CPU(cpu)->env.cpu_state;
351 if (state == CPU_STATE_OPERATING ||
352 state == CPU_STATE_LOAD) {
eb24f7c6
DH
353 if (!disabled_wait(cpu)) {
354 nr_running++;
355 }
75973bfe
DH
356 }
357 }
358
359 return nr_running;
360}
361
eb24f7c6 362unsigned int s390_cpu_halt(S390CPU *cpu)
75973bfe
DH
363{
364 CPUState *cs = CPU(cpu);
eb24f7c6 365 trace_cpu_halt(cs->cpu_index);
75973bfe 366
eb24f7c6
DH
367 if (!cs->halted) {
368 cs->halted = 1;
369 cs->exception_index = EXCP_HLT;
75973bfe 370 }
eb24f7c6
DH
371
372 return s390_count_running_cpus();
75973bfe
DH
373}
374
eb24f7c6 375void s390_cpu_unhalt(S390CPU *cpu)
75973bfe
DH
376{
377 CPUState *cs = CPU(cpu);
eb24f7c6 378 trace_cpu_unhalt(cs->cpu_index);
75973bfe 379
eb24f7c6
DH
380 if (cs->halted) {
381 cs->halted = 0;
382 cs->exception_index = -1;
383 }
384}
385
386unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
387 {
388 trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
389
390 switch (cpu_state) {
391 case CPU_STATE_STOPPED:
392 case CPU_STATE_CHECK_STOP:
393 /* halt the cpu for common infrastructure */
394 s390_cpu_halt(cpu);
395 break;
396 case CPU_STATE_OPERATING:
397 case CPU_STATE_LOAD:
398 /* unhalt the cpu for common infrastructure */
399 s390_cpu_unhalt(cpu);
400 break;
401 default:
402 error_report("Requested CPU state is not a valid S390 CPU state: %u",
403 cpu_state);
404 exit(1);
75973bfe 405 }
c9e659c9
DH
406 if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
407 kvm_s390_set_cpu_state(cpu, cpu_state);
408 }
eb24f7c6 409 cpu->env.cpu_state = cpu_state;
75973bfe
DH
410
411 return s390_count_running_cpus();
412}
413#endif
414
b3820e6c
DH
415static gchar *s390_gdb_arch_name(CPUState *cs)
416{
417 return g_strdup("s390:64-bit");
418}
419
29e4bcb2
AF
420static void s390_cpu_class_init(ObjectClass *oc, void *data)
421{
422 S390CPUClass *scc = S390_CPU_CLASS(oc);
423 CPUClass *cc = CPU_CLASS(scc);
c7396bbb 424 DeviceClass *dc = DEVICE_CLASS(oc);
29e4bcb2 425
c6644fc8 426 scc->next_cpu_id = 0;
1f136632
AF
427 scc->parent_realize = dc->realize;
428 dc->realize = s390_cpu_realizefn;
429
29e4bcb2 430 scc->parent_reset = cc->reset;
29c6157c
CB
431#if !defined(CONFIG_USER_ONLY)
432 scc->load_normal = s390_cpu_load_normal;
433#endif
f5ae2a4f
CB
434 scc->cpu_reset = s390_cpu_reset;
435 scc->initial_cpu_reset = s390_cpu_initial_reset;
436 cc->reset = s390_cpu_full_reset;
8c2e1b00 437 cc->has_work = s390_cpu_has_work;
97a8ea5a 438 cc->do_interrupt = s390_cpu_do_interrupt;
878096ee 439 cc->dump_state = s390_cpu_dump_state;
f45748f1 440 cc->set_pc = s390_cpu_set_pc;
5b50e790
AF
441 cc->gdb_read_register = s390_cpu_gdb_read_register;
442 cc->gdb_write_register = s390_cpu_gdb_write_register;
7510454e
AF
443#ifdef CONFIG_USER_ONLY
444 cc->handle_mmu_fault = s390_cpu_handle_mmu_fault;
445#else
00b941e5 446 cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
ef1df130 447 cc->vmsd = &vmstate_s390_cpu;
9b4f38e1 448 cc->write_elf64_note = s390_cpu_write_elf64_note;
02bb9bbf 449 cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
311918b9 450 cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
00b941e5 451#endif
dbad6b74
PC
452 cc->disas_set_info = s390_cpu_disas_set_info;
453
73d510c9
DH
454 cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
455 cc->gdb_core_xml_file = "s390x-core64.xml";
b3820e6c 456 cc->gdb_arch_name = s390_gdb_arch_name;
4c315c27
MA
457
458 /*
c6644fc8 459 * Reason: s390_cpu_realizefn() calls cpu_exec_init(), which saves
4c315c27
MA
460 * the object in cpus -> dangling pointer after final
461 * object_unref().
462 */
463 dc->cannot_destroy_with_object_finalize_yet = true;
29e4bcb2
AF
464}
465
466static const TypeInfo s390_cpu_type_info = {
467 .name = TYPE_S390_CPU,
468 .parent = TYPE_CPU,
469 .instance_size = sizeof(S390CPU),
8f22e0df 470 .instance_init = s390_cpu_initfn,
d5627ce8 471 .instance_finalize = s390_cpu_finalize,
29e4bcb2
AF
472 .abstract = false,
473 .class_size = sizeof(S390CPUClass),
474 .class_init = s390_cpu_class_init,
475};
476
477static void s390_cpu_register_types(void)
478{
479 type_register_static(&s390_cpu_type_info);
480}
481
482type_init(s390_cpu_register_types)