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 "s390x-internal.h"
27#include "kvm/kvm_s390x.h"
28#include "sysemu/kvm.h"
29#include "sysemu/reset.h"
30#include "qemu/module.h"
31#include "trace.h"
32#include "qapi/qapi-types-machine.h"
33#include "sysemu/hw_accel.h"
34#include "hw/qdev-properties.h"
35#include "fpu/softfloat-helpers.h"
36#include "disas/capstone.h"
37#include "sysemu/tcg.h"
38
39#define CR0_RESET 0xE0UL
40#define CR14_RESET 0xC2000000UL;
41
42void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
43{
44#ifndef CONFIG_USER_ONLY
45 uint64_t old_mask = env->psw.mask;
46#endif
47
48 env->psw.addr = addr;
49 env->psw.mask = mask;
50
51
52 if (!tcg_enabled()) {
53 return;
54 }
55 env->cc_op = (mask >> 44) & 3;
56
57#ifndef CONFIG_USER_ONLY
58 if ((old_mask ^ mask) & PSW_MASK_PER) {
59 s390_cpu_recompute_watchpoints(env_cpu(env));
60 }
61
62 if (mask & PSW_MASK_WAIT) {
63 s390_handle_wait(env_archcpu(env));
64 }
65#endif
66}
67
68uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
69{
70 uint64_t r = env->psw.mask;
71
72 if (tcg_enabled()) {
73 uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
74 env->cc_dst, env->cc_vr);
75
76 assert(cc <= 3);
77 r &= ~PSW_MASK_CC;
78 r |= cc << 44;
79 }
80
81 return r;
82}
83
84static void s390_cpu_set_pc(CPUState *cs, vaddr value)
85{
86 S390CPU *cpu = S390_CPU(cs);
87
88 cpu->env.psw.addr = value;
89}
90
91static vaddr s390_cpu_get_pc(CPUState *cs)
92{
93 S390CPU *cpu = S390_CPU(cs);
94
95 return cpu->env.psw.addr;
96}
97
98static bool s390_cpu_has_work(CPUState *cs)
99{
100 S390CPU *cpu = S390_CPU(cs);
101
102
103 if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD &&
104 s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
105 return false;
106 }
107
108 if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
109 return false;
110 }
111
112 return s390_cpu_has_int(cpu);
113}
114
115
116static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
117{
118 S390CPU *cpu = S390_CPU(s);
119 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
120 CPUS390XState *env = &cpu->env;
121 DeviceState *dev = DEVICE(s);
122
123 scc->parent_reset(dev);
124 cpu->env.sigp_order = 0;
125 s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
126
127 switch (type) {
128 case S390_CPU_RESET_CLEAR:
129 memset(env, 0, offsetof(CPUS390XState, start_initial_reset_fields));
130
131 case S390_CPU_RESET_INITIAL:
132
133 memset(&env->start_initial_reset_fields, 0,
134 offsetof(CPUS390XState, start_normal_reset_fields) -
135 offsetof(CPUS390XState, start_initial_reset_fields));
136
137
138 env->gbea = 1;
139
140
141 env->cregs[0] = CR0_RESET;
142 env->cregs[14] = CR14_RESET;
143
144#if defined(CONFIG_USER_ONLY)
145
146 env->cregs[0] |= CR0_AFP;
147 if (s390_has_feat(S390_FEAT_VECTOR)) {
148 env->cregs[0] |= CR0_VECTOR;
149 }
150#endif
151
152
153 set_float_detect_tininess(float_tininess_before_rounding,
154 &env->fpu_status);
155
156 case S390_CPU_RESET_NORMAL:
157 env->psw.mask &= ~PSW_MASK_RI;
158 memset(&env->start_normal_reset_fields, 0,
159 offsetof(CPUS390XState, end_reset_fields) -
160 offsetof(CPUS390XState, start_normal_reset_fields));
161
162 env->pfault_token = -1UL;
163 env->bpbc = false;
164 break;
165 default:
166 g_assert_not_reached();
167 }
168
169
170 if (kvm_enabled()) {
171 switch (type) {
172 case S390_CPU_RESET_CLEAR:
173 kvm_s390_reset_vcpu_clear(cpu);
174 break;
175 case S390_CPU_RESET_INITIAL:
176 kvm_s390_reset_vcpu_initial(cpu);
177 break;
178 case S390_CPU_RESET_NORMAL:
179 kvm_s390_reset_vcpu_normal(cpu);
180 break;
181 }
182 }
183}
184
185static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
186{
187 info->mach = bfd_mach_s390_64;
188 info->cap_arch = CS_ARCH_SYSZ;
189 info->cap_insn_unit = 2;
190 info->cap_insn_split = 6;
191}
192
193static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
194{
195 CPUState *cs = CPU(dev);
196 S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
197 Error *err = NULL;
198
199
200 s390_realize_cpu_model(cs, &err);
201 if (err) {
202 goto out;
203 }
204
205#if !defined(CONFIG_USER_ONLY)
206 if (!s390_cpu_realize_sysemu(dev, &err)) {
207 goto out;
208 }
209#endif
210
211 cpu_exec_realizefn(cs, &err);
212 if (err != NULL) {
213 goto out;
214 }
215
216#if !defined(CONFIG_USER_ONLY)
217 qemu_register_reset(s390_cpu_machine_reset_cb, S390_CPU(dev));
218#endif
219 s390_cpu_gdb_init(cs);
220 qemu_init_vcpu(cs);
221
222
223
224
225
226
227
228 if (kvm_enabled()) {
229 run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
230 } else {
231 cpu_reset(cs);
232 }
233
234 scc->parent_realize(dev, &err);
235out:
236 error_propagate(errp, err);
237}
238
239static void s390_cpu_initfn(Object *obj)
240{
241 CPUState *cs = CPU(obj);
242 S390CPU *cpu = S390_CPU(obj);
243
244 cpu_set_cpustate_pointers(cpu);
245 cs->exception_index = EXCP_HLT;
246
247#if !defined(CONFIG_USER_ONLY)
248 s390_cpu_init_sysemu(obj);
249#endif
250}
251
252static gchar *s390_gdb_arch_name(CPUState *cs)
253{
254 return g_strdup("s390:64-bit");
255}
256
257static Property s390x_cpu_properties[] = {
258#if !defined(CONFIG_USER_ONLY)
259 DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0),
260#endif
261 DEFINE_PROP_END_OF_LIST()
262};
263
264static void s390_cpu_reset_full(DeviceState *dev)
265{
266 CPUState *s = CPU(dev);
267 return s390_cpu_reset(s, S390_CPU_RESET_CLEAR);
268}
269
270#ifdef CONFIG_TCG
271#include "hw/core/tcg-cpu-ops.h"
272
273static const struct TCGCPUOps s390_tcg_ops = {
274 .initialize = s390x_translate_init,
275 .restore_state_to_opc = s390x_restore_state_to_opc,
276
277#ifdef CONFIG_USER_ONLY
278 .record_sigsegv = s390_cpu_record_sigsegv,
279 .record_sigbus = s390_cpu_record_sigbus,
280#else
281 .tlb_fill = s390_cpu_tlb_fill,
282 .cpu_exec_interrupt = s390_cpu_exec_interrupt,
283 .do_interrupt = s390_cpu_do_interrupt,
284 .debug_excp_handler = s390x_cpu_debug_excp_handler,
285 .do_unaligned_access = s390x_cpu_do_unaligned_access,
286#endif
287};
288#endif
289
290static void s390_cpu_class_init(ObjectClass *oc, void *data)
291{
292 S390CPUClass *scc = S390_CPU_CLASS(oc);
293 CPUClass *cc = CPU_CLASS(scc);
294 DeviceClass *dc = DEVICE_CLASS(oc);
295
296 device_class_set_parent_realize(dc, s390_cpu_realizefn,
297 &scc->parent_realize);
298 device_class_set_props(dc, s390x_cpu_properties);
299 dc->user_creatable = true;
300
301 device_class_set_parent_reset(dc, s390_cpu_reset_full, &scc->parent_reset);
302
303 scc->reset = s390_cpu_reset;
304 cc->class_by_name = s390_cpu_class_by_name,
305 cc->has_work = s390_cpu_has_work;
306 cc->dump_state = s390_cpu_dump_state;
307 cc->set_pc = s390_cpu_set_pc;
308 cc->get_pc = s390_cpu_get_pc;
309 cc->gdb_read_register = s390_cpu_gdb_read_register;
310 cc->gdb_write_register = s390_cpu_gdb_write_register;
311#ifndef CONFIG_USER_ONLY
312 s390_cpu_class_init_sysemu(cc);
313#endif
314 cc->disas_set_info = s390_cpu_disas_set_info;
315 cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
316 cc->gdb_core_xml_file = "s390x-core64.xml";
317 cc->gdb_arch_name = s390_gdb_arch_name;
318
319 s390_cpu_model_class_register_props(oc);
320
321#ifdef CONFIG_TCG
322 cc->tcg_ops = &s390_tcg_ops;
323#endif
324}
325
326static const TypeInfo s390_cpu_type_info = {
327 .name = TYPE_S390_CPU,
328 .parent = TYPE_CPU,
329 .instance_size = sizeof(S390CPU),
330 .instance_align = __alignof__(S390CPU),
331 .instance_init = s390_cpu_initfn,
332
333#ifndef CONFIG_USER_ONLY
334 .instance_finalize = s390_cpu_finalize,
335#endif
336
337 .abstract = true,
338 .class_size = sizeof(S390CPUClass),
339 .class_init = s390_cpu_class_init,
340};
341
342static void s390_cpu_register_types(void)
343{
344 type_register_static(&s390_cpu_type_info);
345}
346
347type_init(s390_cpu_register_types)
348