]>
Commit | Line | Data |
---|---|---|
72ffb631 CYC |
1 | /* |
2 | * QEMU S/390 CPU - System Emulation-only code | |
3 | * | |
4 | * Copyright (c) 2009 Ulrich Hecht | |
5 | * Copyright (c) 2011 Alexander Graf | |
6 | * Copyright (c) 2012 SUSE LINUX Products GmbH | |
7 | * Copyright (c) 2012 IBM Corp. | |
8 | * | |
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. | |
13 | * | |
14 | * This program 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 | * General Public License for more details. | |
18 | * | |
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/>. | |
21 | */ | |
22 | ||
23 | #include "qemu/osdep.h" | |
24 | #include "qapi/error.h" | |
25 | #include "cpu.h" | |
26 | #include "s390x-internal.h" | |
67043607 | 27 | #include "kvm/kvm_s390x.h" |
72ffb631 CYC |
28 | #include "sysemu/kvm.h" |
29 | #include "sysemu/reset.h" | |
30 | #include "qemu/timer.h" | |
31 | #include "trace.h" | |
32 | #include "qapi/qapi-visit-run-state.h" | |
33 | #include "sysemu/hw_accel.h" | |
34 | ||
35 | #include "hw/s390x/pv.h" | |
36 | #include "hw/boards.h" | |
72ffb631 CYC |
37 | #include "sysemu/sysemu.h" |
38 | #include "sysemu/tcg.h" | |
39 | #include "hw/core/sysemu-cpu-ops.h" | |
40 | ||
41 | /* S390CPUClass::load_normal() */ | |
42 | static void s390_cpu_load_normal(CPUState *s) | |
43 | { | |
44 | S390CPU *cpu = S390_CPU(s); | |
45 | uint64_t spsw; | |
46 | ||
47 | if (!s390_is_pv()) { | |
48 | spsw = ldq_phys(s->as, 0); | |
49 | cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL; | |
50 | /* | |
51 | * Invert short psw indication, so SIE will report a specification | |
52 | * exception if it was not set. | |
53 | */ | |
54 | cpu->env.psw.mask ^= PSW_MASK_SHORTPSW; | |
55 | cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR; | |
56 | } else { | |
57 | /* | |
58 | * Firmware requires us to set the load state before we set | |
59 | * the cpu to operating on protected guests. | |
60 | */ | |
61 | s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu); | |
62 | } | |
63 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); | |
64 | } | |
65 | ||
66 | void s390_cpu_machine_reset_cb(void *opaque) | |
67 | { | |
68 | S390CPU *cpu = opaque; | |
69 | ||
70 | run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL); | |
71 | } | |
72 | ||
73 | static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs) | |
74 | { | |
75 | GuestPanicInformation *panic_info; | |
76 | S390CPU *cpu = S390_CPU(cs); | |
77 | ||
78 | cpu_synchronize_state(cs); | |
b21e2380 | 79 | panic_info = g_new0(GuestPanicInformation, 1); |
72ffb631 CYC |
80 | |
81 | panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390; | |
82 | panic_info->u.s390.core = cpu->env.core_id; | |
83 | panic_info->u.s390.psw_mask = cpu->env.psw.mask; | |
84 | panic_info->u.s390.psw_addr = cpu->env.psw.addr; | |
85 | panic_info->u.s390.reason = cpu->env.crash_reason; | |
86 | ||
87 | return panic_info; | |
88 | } | |
89 | ||
90 | static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v, | |
91 | const char *name, void *opaque, | |
92 | Error **errp) | |
93 | { | |
94 | CPUState *cs = CPU(obj); | |
95 | GuestPanicInformation *panic_info; | |
96 | ||
97 | if (!cs->crash_occurred) { | |
98 | error_setg(errp, "No crash occurred"); | |
99 | return; | |
100 | } | |
101 | ||
102 | panic_info = s390_cpu_get_crash_info(cs); | |
103 | ||
104 | visit_type_GuestPanicInformation(v, "crash-information", &panic_info, | |
105 | errp); | |
106 | qapi_free_GuestPanicInformation(panic_info); | |
107 | } | |
108 | ||
109 | void s390_cpu_init_sysemu(Object *obj) | |
110 | { | |
111 | CPUState *cs = CPU(obj); | |
112 | S390CPU *cpu = S390_CPU(obj); | |
113 | ||
114 | cs->start_powered_off = true; | |
115 | object_property_add(obj, "crash-information", "GuestPanicInformation", | |
116 | s390_cpu_get_crash_info_qom, NULL, NULL, NULL); | |
117 | cpu->env.tod_timer = | |
118 | timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); | |
119 | cpu->env.cpu_timer = | |
120 | timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); | |
121 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); | |
122 | } | |
123 | ||
124 | bool s390_cpu_realize_sysemu(DeviceState *dev, Error **errp) | |
125 | { | |
126 | S390CPU *cpu = S390_CPU(dev); | |
127 | MachineState *ms = MACHINE(qdev_get_machine()); | |
128 | unsigned int max_cpus = ms->smp.max_cpus; | |
129 | ||
130 | if (cpu->env.core_id >= max_cpus) { | |
131 | error_setg(errp, "Unable to add CPU with core-id: %" PRIu32 | |
132 | ", maximum core-id: %d", cpu->env.core_id, | |
133 | max_cpus - 1); | |
134 | return false; | |
135 | } | |
136 | ||
137 | if (cpu_exists(cpu->env.core_id)) { | |
138 | error_setg(errp, "Unable to add CPU with core-id: %" PRIu32 | |
139 | ", it already exists", cpu->env.core_id); | |
140 | return false; | |
141 | } | |
142 | ||
143 | /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */ | |
144 | CPU(cpu)->cpu_index = cpu->env.core_id; | |
145 | return true; | |
146 | } | |
147 | ||
148 | void s390_cpu_finalize(Object *obj) | |
149 | { | |
150 | S390CPU *cpu = S390_CPU(obj); | |
151 | ||
152 | timer_free(cpu->env.tod_timer); | |
153 | timer_free(cpu->env.cpu_timer); | |
154 | ||
155 | qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu); | |
156 | g_free(cpu->irqstate); | |
157 | } | |
158 | ||
159 | static const struct SysemuCPUOps s390_sysemu_ops = { | |
160 | .get_phys_page_debug = s390_cpu_get_phys_page_debug, | |
161 | .get_crash_info = s390_cpu_get_crash_info, | |
162 | .write_elf64_note = s390_cpu_write_elf64_note, | |
163 | .legacy_vmsd = &vmstate_s390_cpu, | |
164 | }; | |
165 | ||
166 | void s390_cpu_class_init_sysemu(CPUClass *cc) | |
167 | { | |
168 | S390CPUClass *scc = S390_CPU_CLASS(cc); | |
169 | ||
170 | scc->load_normal = s390_cpu_load_normal; | |
171 | cc->sysemu_ops = &s390_sysemu_ops; | |
172 | } | |
173 | ||
174 | static bool disabled_wait(CPUState *cpu) | |
175 | { | |
176 | return cpu->halted && !(S390_CPU(cpu)->env.psw.mask & | |
177 | (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK)); | |
178 | } | |
179 | ||
180 | static unsigned s390_count_running_cpus(void) | |
181 | { | |
182 | CPUState *cpu; | |
183 | int nr_running = 0; | |
184 | ||
185 | CPU_FOREACH(cpu) { | |
186 | uint8_t state = S390_CPU(cpu)->env.cpu_state; | |
187 | if (state == S390_CPU_STATE_OPERATING || | |
188 | state == S390_CPU_STATE_LOAD) { | |
189 | if (!disabled_wait(cpu)) { | |
190 | nr_running++; | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
195 | return nr_running; | |
196 | } | |
197 | ||
198 | unsigned int s390_cpu_halt(S390CPU *cpu) | |
199 | { | |
200 | CPUState *cs = CPU(cpu); | |
201 | trace_cpu_halt(cs->cpu_index); | |
202 | ||
203 | if (!cs->halted) { | |
204 | cs->halted = 1; | |
205 | cs->exception_index = EXCP_HLT; | |
206 | } | |
207 | ||
208 | return s390_count_running_cpus(); | |
209 | } | |
210 | ||
211 | void s390_cpu_unhalt(S390CPU *cpu) | |
212 | { | |
213 | CPUState *cs = CPU(cpu); | |
214 | trace_cpu_unhalt(cs->cpu_index); | |
215 | ||
216 | if (cs->halted) { | |
217 | cs->halted = 0; | |
218 | cs->exception_index = -1; | |
219 | } | |
220 | } | |
221 | ||
222 | unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) | |
223 | { | |
224 | trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state); | |
225 | ||
226 | switch (cpu_state) { | |
227 | case S390_CPU_STATE_STOPPED: | |
228 | case S390_CPU_STATE_CHECK_STOP: | |
229 | /* halt the cpu for common infrastructure */ | |
230 | s390_cpu_halt(cpu); | |
231 | break; | |
232 | case S390_CPU_STATE_OPERATING: | |
233 | case S390_CPU_STATE_LOAD: | |
234 | /* | |
235 | * Starting a CPU with a PSW WAIT bit set: | |
236 | * KVM: handles this internally and triggers another WAIT exit. | |
237 | * TCG: will actually try to continue to run. Don't unhalt, will | |
238 | * be done when the CPU actually has work (an interrupt). | |
239 | */ | |
240 | if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) { | |
241 | s390_cpu_unhalt(cpu); | |
242 | } | |
243 | break; | |
244 | default: | |
245 | error_report("Requested CPU state is not a valid S390 CPU state: %u", | |
246 | cpu_state); | |
247 | exit(1); | |
248 | } | |
249 | if (kvm_enabled() && cpu->env.cpu_state != cpu_state) { | |
250 | kvm_s390_set_cpu_state(cpu, cpu_state); | |
251 | } | |
252 | cpu->env.cpu_state = cpu_state; | |
253 | ||
254 | return s390_count_running_cpus(); | |
255 | } | |
256 | ||
257 | int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) | |
258 | { | |
259 | if (kvm_enabled()) { | |
260 | return kvm_s390_set_mem_limit(new_limit, hw_limit); | |
261 | } | |
262 | return 0; | |
263 | } | |
264 | ||
265 | void s390_set_max_pagesize(uint64_t pagesize, Error **errp) | |
266 | { | |
267 | if (kvm_enabled()) { | |
268 | kvm_s390_set_max_pagesize(pagesize, errp); | |
269 | } | |
270 | } | |
271 | ||
272 | void s390_cmma_reset(void) | |
273 | { | |
274 | if (kvm_enabled()) { | |
275 | kvm_s390_cmma_reset(); | |
276 | } | |
277 | } | |
278 | ||
279 | int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id, | |
280 | int vq, bool assign) | |
281 | { | |
282 | if (kvm_enabled()) { | |
283 | return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign); | |
284 | } else { | |
285 | return 0; | |
286 | } | |
287 | } | |
288 | ||
289 | void s390_crypto_reset(void) | |
290 | { | |
291 | if (kvm_enabled()) { | |
292 | kvm_s390_crypto_reset(); | |
293 | } | |
294 | } | |
295 | ||
296 | void s390_enable_css_support(S390CPU *cpu) | |
297 | { | |
298 | if (kvm_enabled()) { | |
299 | kvm_s390_enable_css_support(cpu); | |
300 | } | |
301 | } | |
302 | ||
303 | void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg) | |
304 | { | |
305 | if (kvm_enabled()) { | |
306 | kvm_s390_set_diag318(cs, arg.host_ulong); | |
307 | } | |
308 | } |