]>
Commit | Line | Data |
---|---|---|
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 | 8 | * |
44699e1c TH |
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. | |
29e4bcb2 | 13 | * |
44699e1c | 14 | * This program is distributed in the hope that it will be useful, |
29e4bcb2 AF |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
44699e1c | 17 | * General Public License for more details. |
29e4bcb2 | 18 | * |
44699e1c TH |
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/>. | |
29e4bcb2 AF |
21 | */ |
22 | ||
9615495a | 23 | #include "qemu/osdep.h" |
da34e65c | 24 | #include "qapi/error.h" |
564b863d | 25 | #include "cpu.h" |
b6b47223 | 26 | #include "s390x-internal.h" |
67043607 | 27 | #include "kvm/kvm_s390x.h" |
f16bbb9b | 28 | #include "sysemu/kvm.h" |
71e8a915 | 29 | #include "sysemu/reset.h" |
0b8fa32f | 30 | #include "qemu/module.h" |
eb24f7c6 | 31 | #include "trace.h" |
8ac25c84 | 32 | #include "qapi/qapi-types-machine.h" |
4ada99ad | 33 | #include "sysemu/hw_accel.h" |
ca5c1457 | 34 | #include "hw/qdev-properties.h" |
5f8ab000 | 35 | #include "fpu/softfloat-helpers.h" |
3d562845 | 36 | #include "disas/capstone.h" |
98be64d2 | 37 | #include "sysemu/tcg.h" |
904e5fd5 | 38 | |
70bada03 JF |
39 | #define CR0_RESET 0xE0UL |
40 | #define CR14_RESET 0xC2000000UL; | |
41 | ||
98be64d2 CYC |
42 | void 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 | /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */ | |
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 | ||
68 | uint64_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 | ||
f45748f1 AF |
84 | static 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 | ||
e4fdf9df RH |
91 | static vaddr s390_cpu_get_pc(CPUState *cs) |
92 | { | |
93 | S390CPU *cpu = S390_CPU(cs); | |
94 | ||
95 | return cpu->env.psw.addr; | |
96 | } | |
97 | ||
8c2e1b00 AF |
98 | static bool s390_cpu_has_work(CPUState *cs) |
99 | { | |
100 | S390CPU *cpu = S390_CPU(cs); | |
8c2e1b00 | 101 | |
4beab671 | 102 | /* STOPPED cpus can never wake up */ |
9d0306df VM |
103 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD && |
104 | s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) { | |
4beab671 DH |
105 | return false; |
106 | } | |
107 | ||
8417f904 DH |
108 | if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { |
109 | return false; | |
110 | } | |
111 | ||
112 | return s390_cpu_has_int(cpu); | |
8c2e1b00 AF |
113 | } |
114 | ||
eac4f827 JF |
115 | /* S390CPUClass::reset() */ |
116 | static void s390_cpu_reset(CPUState *s, cpu_reset_type type) | |
29e4bcb2 AF |
117 | { |
118 | S390CPU *cpu = S390_CPU(s); | |
119 | S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); | |
120 | CPUS390XState *env = &cpu->env; | |
781c67ca | 121 | DeviceState *dev = DEVICE(s); |
29e4bcb2 | 122 | |
781c67ca | 123 | scc->parent_reset(dev); |
18ff9494 | 124 | cpu->env.sigp_order = 0; |
9d0306df | 125 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
eac4f827 JF |
126 | |
127 | switch (type) { | |
eb8adcc3 JF |
128 | case S390_CPU_RESET_CLEAR: |
129 | memset(env, 0, offsetof(CPUS390XState, start_initial_reset_fields)); | |
130 | /* fall through */ | |
81b92223 JF |
131 | case S390_CPU_RESET_INITIAL: |
132 | /* initial reset does not clear everything! */ | |
133 | memset(&env->start_initial_reset_fields, 0, | |
e893baee | 134 | offsetof(CPUS390XState, start_normal_reset_fields) - |
81b92223 JF |
135 | offsetof(CPUS390XState, start_initial_reset_fields)); |
136 | ||
137 | /* architectured initial value for Breaking-Event-Address register */ | |
138 | env->gbea = 1; | |
139 | ||
140 | /* architectured initial values for CR 0 and 14 */ | |
141 | env->cregs[0] = CR0_RESET; | |
142 | env->cregs[14] = CR14_RESET; | |
143 | ||
eb8adcc3 JF |
144 | #if defined(CONFIG_USER_ONLY) |
145 | /* user mode should always be allowed to use the full FPU */ | |
146 | env->cregs[0] |= CR0_AFP; | |
147 | if (s390_has_feat(S390_FEAT_VECTOR)) { | |
148 | env->cregs[0] |= CR0_VECTOR; | |
149 | } | |
150 | #endif | |
151 | ||
81b92223 JF |
152 | /* tininess for underflow is detected before rounding */ |
153 | set_float_detect_tininess(float_tininess_before_rounding, | |
154 | &env->fpu_status); | |
155 | /* fall through */ | |
eac4f827 | 156 | case S390_CPU_RESET_NORMAL: |
e893baee JF |
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 | ||
eac4f827 JF |
162 | env->pfault_token = -1UL; |
163 | env->bpbc = false; | |
164 | break; | |
165 | default: | |
166 | g_assert_not_reached(); | |
167 | } | |
4a33565f | 168 | |
49f5c9e9 | 169 | /* Reset state inside the kernel that we cannot access yet from QEMU. */ |
b91a0394 JF |
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 | } | |
49f5c9e9 | 182 | } |
f5ae2a4f CB |
183 | } |
184 | ||
dbad6b74 PC |
185 | static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) |
186 | { | |
187 | info->mach = bfd_mach_s390_64; | |
3d562845 RH |
188 | info->cap_arch = CS_ARCH_SYSZ; |
189 | info->cap_insn_unit = 2; | |
190 | info->cap_insn_split = 6; | |
dbad6b74 PC |
191 | } |
192 | ||
1f136632 AF |
193 | static void s390_cpu_realizefn(DeviceState *dev, Error **errp) |
194 | { | |
14a10fc3 | 195 | CPUState *cs = CPU(dev); |
1f136632 | 196 | S390CPUClass *scc = S390_CPU_GET_CLASS(dev); |
c6644fc8 MR |
197 | Error *err = NULL; |
198 | ||
41868f84 DH |
199 | /* the model has to be realized before qemu_init_vcpu() due to kvm */ |
200 | s390_realize_cpu_model(cs, &err); | |
201 | if (err) { | |
202 | goto out; | |
203 | } | |
204 | ||
96b1a8bb | 205 | #if !defined(CONFIG_USER_ONLY) |
72ffb631 | 206 | if (!s390_cpu_realize_sysemu(dev, &err)) { |
96b1a8bb MR |
207 | goto out; |
208 | } | |
1e70ba24 DH |
209 | #endif |
210 | ||
ce5b1bbf | 211 | cpu_exec_realizefn(cs, &err); |
c6644fc8 | 212 | if (err != NULL) { |
96b1a8bb | 213 | goto out; |
c6644fc8 | 214 | } |
1f136632 | 215 | |
c6644fc8 | 216 | #if !defined(CONFIG_USER_ONLY) |
72ffb631 | 217 | qemu_register_reset(s390_cpu_machine_reset_cb, S390_CPU(dev)); |
c6644fc8 | 218 | #endif |
73d510c9 | 219 | s390_cpu_gdb_init(cs); |
14a10fc3 | 220 | qemu_init_vcpu(cs); |
d66b43c8 DH |
221 | |
222 | /* | |
223 | * KVM requires the initial CPU reset ioctl to be executed on the target | |
224 | * CPU thread. CPU hotplug under single-threaded TCG will not work with | |
225 | * run_on_cpu(), as run_on_cpu() will not work properly if called while | |
226 | * the main thread is already running but the CPU hasn't been realized. | |
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 | } | |
1f136632 | 233 | |
96b1a8bb | 234 | scc->parent_realize(dev, &err); |
96b1a8bb MR |
235 | out: |
236 | error_propagate(errp, err); | |
237 | } | |
238 | ||
8f22e0df AF |
239 | static void s390_cpu_initfn(Object *obj) |
240 | { | |
c05efcb1 | 241 | CPUState *cs = CPU(obj); |
8f22e0df | 242 | S390CPU *cpu = S390_CPU(obj); |
8f22e0df | 243 | |
7506ed90 | 244 | cpu_set_cpustate_pointers(cpu); |
ef3027af | 245 | cs->exception_index = EXCP_HLT; |
8f22e0df | 246 | |
d5627ce8 | 247 | #if !defined(CONFIG_USER_ONLY) |
72ffb631 | 248 | s390_cpu_init_sysemu(obj); |
d5627ce8 AF |
249 | #endif |
250 | } | |
251 | ||
b3820e6c DH |
252 | static gchar *s390_gdb_arch_name(CPUState *cs) |
253 | { | |
254 | return g_strdup("s390:64-bit"); | |
255 | } | |
256 | ||
ca5c1457 | 257 | static Property s390x_cpu_properties[] = { |
1e70ba24 | 258 | #if !defined(CONFIG_USER_ONLY) |
ca5c1457 | 259 | DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0), |
1e70ba24 | 260 | #endif |
ca5c1457 DH |
261 | DEFINE_PROP_END_OF_LIST() |
262 | }; | |
263 | ||
781c67ca | 264 | static void s390_cpu_reset_full(DeviceState *dev) |
eb8adcc3 | 265 | { |
781c67ca | 266 | CPUState *s = CPU(dev); |
eb8adcc3 JF |
267 | return s390_cpu_reset(s, S390_CPU_RESET_CLEAR); |
268 | } | |
269 | ||
78271684 CF |
270 | #ifdef CONFIG_TCG |
271 | #include "hw/core/tcg-cpu-ops.h" | |
272 | ||
11906557 | 273 | static const struct TCGCPUOps s390_tcg_ops = { |
78271684 | 274 | .initialize = s390x_translate_init, |
78271684 | 275 | |
c8e7fef1 RH |
276 | #ifdef CONFIG_USER_ONLY |
277 | .record_sigsegv = s390_cpu_record_sigsegv, | |
5bcbf356 | 278 | .record_sigbus = s390_cpu_record_sigbus, |
c8e7fef1 RH |
279 | #else |
280 | .tlb_fill = s390_cpu_tlb_fill, | |
78271684 CF |
281 | .cpu_exec_interrupt = s390_cpu_exec_interrupt, |
282 | .do_interrupt = s390_cpu_do_interrupt, | |
283 | .debug_excp_handler = s390x_cpu_debug_excp_handler, | |
284 | .do_unaligned_access = s390x_cpu_do_unaligned_access, | |
285 | #endif /* !CONFIG_USER_ONLY */ | |
286 | }; | |
287 | #endif /* CONFIG_TCG */ | |
288 | ||
29e4bcb2 AF |
289 | static void s390_cpu_class_init(ObjectClass *oc, void *data) |
290 | { | |
291 | S390CPUClass *scc = S390_CPU_CLASS(oc); | |
292 | CPUClass *cc = CPU_CLASS(scc); | |
c7396bbb | 293 | DeviceClass *dc = DEVICE_CLASS(oc); |
29e4bcb2 | 294 | |
bf853881 PMD |
295 | device_class_set_parent_realize(dc, s390_cpu_realizefn, |
296 | &scc->parent_realize); | |
4f67d30b | 297 | device_class_set_props(dc, s390x_cpu_properties); |
0347ab84 | 298 | dc->user_creatable = true; |
1f136632 | 299 | |
781c67ca | 300 | device_class_set_parent_reset(dc, s390_cpu_reset_full, &scc->parent_reset); |
72ffb631 | 301 | |
eac4f827 | 302 | scc->reset = s390_cpu_reset; |
41868f84 | 303 | cc->class_by_name = s390_cpu_class_by_name, |
8c2e1b00 | 304 | cc->has_work = s390_cpu_has_work; |
878096ee | 305 | cc->dump_state = s390_cpu_dump_state; |
f45748f1 | 306 | cc->set_pc = s390_cpu_set_pc; |
e4fdf9df | 307 | cc->get_pc = s390_cpu_get_pc; |
5b50e790 AF |
308 | cc->gdb_read_register = s390_cpu_gdb_read_register; |
309 | cc->gdb_write_register = s390_cpu_gdb_write_register; | |
82851985 | 310 | #ifndef CONFIG_USER_ONLY |
72ffb631 | 311 | s390_cpu_class_init_sysemu(cc); |
00b941e5 | 312 | #endif |
dbad6b74 | 313 | cc->disas_set_info = s390_cpu_disas_set_info; |
73d510c9 DH |
314 | cc->gdb_num_core_regs = S390_NUM_CORE_REGS; |
315 | cc->gdb_core_xml_file = "s390x-core64.xml"; | |
b3820e6c | 316 | cc->gdb_arch_name = s390_gdb_arch_name; |
4c315c27 | 317 | |
6efadc90 | 318 | s390_cpu_model_class_register_props(oc); |
78271684 CF |
319 | |
320 | #ifdef CONFIG_TCG | |
321 | cc->tcg_ops = &s390_tcg_ops; | |
322 | #endif /* CONFIG_TCG */ | |
29e4bcb2 AF |
323 | } |
324 | ||
325 | static const TypeInfo s390_cpu_type_info = { | |
326 | .name = TYPE_S390_CPU, | |
327 | .parent = TYPE_CPU, | |
328 | .instance_size = sizeof(S390CPU), | |
f62192a2 | 329 | .instance_align = __alignof__(S390CPU), |
8f22e0df | 330 | .instance_init = s390_cpu_initfn, |
72ffb631 CYC |
331 | |
332 | #ifndef CONFIG_USER_ONLY | |
d5627ce8 | 333 | .instance_finalize = s390_cpu_finalize, |
72ffb631 CYC |
334 | #endif /* !CONFIG_USER_ONLY */ |
335 | ||
41868f84 | 336 | .abstract = true, |
29e4bcb2 AF |
337 | .class_size = sizeof(S390CPUClass), |
338 | .class_init = s390_cpu_class_init, | |
339 | }; | |
340 | ||
341 | static void s390_cpu_register_types(void) | |
342 | { | |
343 | type_register_static(&s390_cpu_type_info); | |
344 | } | |
345 | ||
346 | type_init(s390_cpu_register_types) |