]>
Commit | Line | Data |
---|---|---|
74b4c74d DH |
1 | /* |
2 | * s390x SIGP instruction handling | |
3 | * | |
4 | * Copyright (c) 2009 Alexander Graf <agraf@suse.de> | |
5 | * Copyright IBM Corp. 2012 | |
6 | * | |
7 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
8 | * See the COPYING file in the top-level directory. | |
9 | */ | |
10 | ||
11 | #include "qemu/osdep.h" | |
74b4c74d | 12 | #include "cpu.h" |
b6b47223 | 13 | #include "s390x-internal.h" |
74b4c74d | 14 | #include "sysemu/hw_accel.h" |
54d31236 | 15 | #include "sysemu/runstate.h" |
74b4c74d | 16 | #include "exec/address-spaces.h" |
b1ab5f60 | 17 | #include "exec/exec-all.h" |
14a48c1d | 18 | #include "sysemu/tcg.h" |
74b4c74d | 19 | #include "trace.h" |
8ac25c84 | 20 | #include "qapi/qapi-types-machine.h" |
74b4c74d DH |
21 | |
22 | QemuMutex qemu_sigp_mutex; | |
23 | ||
24 | typedef struct SigpInfo { | |
25 | uint64_t param; | |
26 | int cc; | |
27 | uint64_t *status_reg; | |
28 | } SigpInfo; | |
29 | ||
30 | static void set_sigp_status(SigpInfo *si, uint64_t status) | |
31 | { | |
32 | *si->status_reg &= 0xffffffff00000000ULL; | |
33 | *si->status_reg |= status; | |
34 | si->cc = SIGP_CC_STATUS_STORED; | |
35 | } | |
36 | ||
302230fc DH |
37 | static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si) |
38 | { | |
39 | uint8_t state = s390_cpu_get_state(dst_cpu); | |
40 | bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL; | |
41 | uint64_t status = 0; | |
42 | ||
43 | if (!tcg_enabled()) { | |
44 | /* handled in KVM */ | |
45 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
46 | return; | |
47 | } | |
48 | ||
49 | /* sensing without locks is racy, but it's the same for real hw */ | |
9d0306df | 50 | if (state != S390_CPU_STATE_STOPPED && !ext_call) { |
302230fc DH |
51 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
52 | } else { | |
53 | if (ext_call) { | |
54 | status |= SIGP_STAT_EXT_CALL_PENDING; | |
55 | } | |
9d0306df | 56 | if (state == S390_CPU_STATE_STOPPED) { |
302230fc DH |
57 | status |= SIGP_STAT_STOPPED; |
58 | } | |
59 | set_sigp_status(si, status); | |
60 | } | |
61 | } | |
62 | ||
070aa1a4 DH |
63 | static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si) |
64 | { | |
65 | int ret; | |
66 | ||
67 | if (!tcg_enabled()) { | |
68 | /* handled in KVM */ | |
69 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
70 | return; | |
71 | } | |
72 | ||
73 | ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id); | |
74 | if (!ret) { | |
75 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
76 | } else { | |
77 | set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING); | |
78 | } | |
79 | } | |
80 | ||
c50105d4 DH |
81 | static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si) |
82 | { | |
83 | if (!tcg_enabled()) { | |
84 | /* handled in KVM */ | |
85 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
86 | return; | |
87 | } | |
88 | ||
89 | cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id); | |
90 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
91 | } | |
92 | ||
74b4c74d DH |
93 | static void sigp_start(CPUState *cs, run_on_cpu_data arg) |
94 | { | |
95 | S390CPU *cpu = S390_CPU(cs); | |
96 | SigpInfo *si = arg.host_ptr; | |
97 | ||
9d0306df | 98 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
74b4c74d DH |
99 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
100 | return; | |
101 | } | |
102 | ||
9d0306df | 103 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
74b4c74d DH |
104 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
105 | } | |
106 | ||
107 | static void sigp_stop(CPUState *cs, run_on_cpu_data arg) | |
108 | { | |
109 | S390CPU *cpu = S390_CPU(cs); | |
110 | SigpInfo *si = arg.host_ptr; | |
111 | ||
9d0306df | 112 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) { |
74b4c74d DH |
113 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
114 | return; | |
115 | } | |
116 | ||
117 | /* disabled wait - sleeping in user space */ | |
118 | if (cs->halted) { | |
9d0306df | 119 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
74b4c74d DH |
120 | } else { |
121 | /* execute the stop function */ | |
122 | cpu->env.sigp_order = SIGP_STOP; | |
123 | cpu_inject_stop(cpu); | |
124 | } | |
125 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
126 | } | |
127 | ||
128 | static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg) | |
129 | { | |
130 | S390CPU *cpu = S390_CPU(cs); | |
131 | SigpInfo *si = arg.host_ptr; | |
132 | ||
133 | /* disabled wait - sleeping in user space */ | |
9d0306df VM |
134 | if (s390_cpu_get_state(cpu) == S390_CPU_STATE_OPERATING && cs->halted) { |
135 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); | |
74b4c74d DH |
136 | } |
137 | ||
138 | switch (s390_cpu_get_state(cpu)) { | |
9d0306df | 139 | case S390_CPU_STATE_OPERATING: |
74b4c74d DH |
140 | cpu->env.sigp_order = SIGP_STOP_STORE_STATUS; |
141 | cpu_inject_stop(cpu); | |
59b9b518 | 142 | /* store will be performed in do_stop_interrupt() */ |
74b4c74d | 143 | break; |
9d0306df | 144 | case S390_CPU_STATE_STOPPED: |
74b4c74d DH |
145 | /* already stopped, just store the status */ |
146 | cpu_synchronize_state(cs); | |
147 | s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true); | |
148 | break; | |
149 | } | |
150 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
151 | } | |
152 | ||
153 | static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg) | |
154 | { | |
155 | S390CPU *cpu = S390_CPU(cs); | |
156 | SigpInfo *si = arg.host_ptr; | |
157 | uint32_t address = si->param & 0x7ffffe00u; | |
158 | ||
159 | /* cpu has to be stopped */ | |
9d0306df | 160 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
74b4c74d DH |
161 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
162 | return; | |
163 | } | |
164 | ||
165 | cpu_synchronize_state(cs); | |
166 | ||
167 | if (s390_store_status(cpu, address, false)) { | |
168 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); | |
169 | return; | |
170 | } | |
171 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
172 | } | |
173 | ||
174 | #define ADTL_SAVE_LC_MASK 0xfUL | |
175 | static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg) | |
176 | { | |
177 | S390CPU *cpu = S390_CPU(cs); | |
178 | SigpInfo *si = arg.host_ptr; | |
179 | uint8_t lc = si->param & ADTL_SAVE_LC_MASK; | |
180 | hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK; | |
181 | hwaddr len = 1UL << (lc ? lc : 10); | |
182 | ||
183 | if (!s390_has_feat(S390_FEAT_VECTOR) && | |
184 | !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) { | |
185 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
186 | return; | |
187 | } | |
188 | ||
189 | /* cpu has to be stopped */ | |
9d0306df | 190 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
74b4c74d DH |
191 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
192 | return; | |
193 | } | |
194 | ||
195 | /* address must be aligned to length */ | |
196 | if (addr & (len - 1)) { | |
197 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); | |
198 | return; | |
199 | } | |
200 | ||
201 | /* no GS: only lc == 0 is valid */ | |
202 | if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) && | |
203 | lc != 0) { | |
204 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); | |
205 | return; | |
206 | } | |
207 | ||
208 | /* GS: 0, 10, 11, 12 are valid */ | |
209 | if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && | |
210 | lc != 0 && | |
211 | lc != 10 && | |
212 | lc != 11 && | |
213 | lc != 12) { | |
214 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); | |
215 | return; | |
216 | } | |
217 | ||
218 | cpu_synchronize_state(cs); | |
219 | ||
220 | if (s390_store_adtl_status(cpu, addr, len)) { | |
221 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); | |
222 | return; | |
223 | } | |
224 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
225 | } | |
226 | ||
227 | static void sigp_restart(CPUState *cs, run_on_cpu_data arg) | |
228 | { | |
229 | S390CPU *cpu = S390_CPU(cs); | |
230 | SigpInfo *si = arg.host_ptr; | |
231 | ||
232 | switch (s390_cpu_get_state(cpu)) { | |
9d0306df | 233 | case S390_CPU_STATE_STOPPED: |
74b4c74d DH |
234 | /* the restart irq has to be delivered prior to any other pending irq */ |
235 | cpu_synchronize_state(cs); | |
741a4ec1 DH |
236 | /* |
237 | * Set OPERATING (and unhalting) before loading the restart PSW. | |
e2b2a864 RH |
238 | * s390_cpu_set_psw() will then properly halt the CPU again if |
239 | * necessary (TCG). | |
741a4ec1 | 240 | */ |
9d0306df | 241 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
741a4ec1 | 242 | do_restart_interrupt(&cpu->env); |
74b4c74d | 243 | break; |
9d0306df | 244 | case S390_CPU_STATE_OPERATING: |
74b4c74d DH |
245 | cpu_inject_restart(cpu); |
246 | break; | |
247 | } | |
248 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
249 | } | |
250 | ||
251 | static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg) | |
252 | { | |
253 | S390CPU *cpu = S390_CPU(cs); | |
254 | S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); | |
255 | SigpInfo *si = arg.host_ptr; | |
256 | ||
257 | cpu_synchronize_state(cs); | |
81b92223 | 258 | scc->reset(cs, S390_CPU_RESET_INITIAL); |
74b4c74d DH |
259 | cpu_synchronize_post_reset(cs); |
260 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
261 | } | |
262 | ||
263 | static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg) | |
264 | { | |
265 | S390CPU *cpu = S390_CPU(cs); | |
266 | S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); | |
267 | SigpInfo *si = arg.host_ptr; | |
268 | ||
269 | cpu_synchronize_state(cs); | |
eac4f827 | 270 | scc->reset(cs, S390_CPU_RESET_NORMAL); |
74b4c74d DH |
271 | cpu_synchronize_post_reset(cs); |
272 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
273 | } | |
274 | ||
275 | static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg) | |
276 | { | |
277 | S390CPU *cpu = S390_CPU(cs); | |
278 | SigpInfo *si = arg.host_ptr; | |
279 | uint32_t addr = si->param & 0x7fffe000u; | |
280 | ||
281 | cpu_synchronize_state(cs); | |
282 | ||
283 | if (!address_space_access_valid(&address_space_memory, addr, | |
fddffa42 PM |
284 | sizeof(struct LowCore), false, |
285 | MEMTXATTRS_UNSPECIFIED)) { | |
74b4c74d DH |
286 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
287 | return; | |
288 | } | |
289 | ||
290 | /* cpu has to be stopped */ | |
9d0306df | 291 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
74b4c74d DH |
292 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
293 | return; | |
294 | } | |
295 | ||
296 | cpu->env.psa = addr; | |
b376a554 | 297 | tlb_flush(cs); |
74b4c74d DH |
298 | cpu_synchronize_post_init(cs); |
299 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
300 | } | |
301 | ||
a6880d21 DH |
302 | static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, |
303 | SigpInfo *si) | |
304 | { | |
305 | const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT; | |
306 | uint16_t p_asn, s_asn, asn; | |
307 | uint64_t psw_addr, psw_mask; | |
308 | bool idle; | |
309 | ||
310 | if (!tcg_enabled()) { | |
311 | /* handled in KVM */ | |
312 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
313 | return; | |
314 | } | |
315 | ||
316 | /* this looks racy, but these values are only used when STOPPED */ | |
317 | idle = CPU(dst_cpu)->halted; | |
318 | psw_addr = dst_cpu->env.psw.addr; | |
319 | psw_mask = dst_cpu->env.psw.mask; | |
320 | asn = si->param; | |
321 | p_asn = dst_cpu->env.cregs[4] & 0xffff; /* Primary ASN */ | |
322 | s_asn = dst_cpu->env.cregs[3] & 0xffff; /* Secondary ASN */ | |
323 | ||
9d0306df | 324 | if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED || |
a6880d21 DH |
325 | (psw_mask & psw_int_mask) != psw_int_mask || |
326 | (idle && psw_addr != 0) || | |
327 | (!idle && (asn == p_asn || asn == s_asn))) { | |
328 | cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id); | |
329 | } else { | |
330 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); | |
331 | } | |
332 | ||
333 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
334 | } | |
335 | ||
d1b468bc DH |
336 | static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si) |
337 | { | |
338 | if (!tcg_enabled()) { | |
339 | /* handled in KVM */ | |
340 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
341 | return; | |
342 | } | |
343 | ||
344 | /* sensing without locks is racy, but it's the same for real hw */ | |
345 | if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) { | |
346 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
347 | return; | |
348 | } | |
349 | ||
350 | /* If halted (which includes also STOPPED), it is not running */ | |
351 | if (CPU(dst_cpu)->halted) { | |
d1b468bc | 352 | set_sigp_status(si, SIGP_STAT_NOT_RUNNING); |
4103500e JF |
353 | } else { |
354 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
d1b468bc DH |
355 | } |
356 | } | |
357 | ||
070aa1a4 | 358 | static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order, |
74b4c74d DH |
359 | uint64_t param, uint64_t *status_reg) |
360 | { | |
361 | SigpInfo si = { | |
362 | .param = param, | |
363 | .status_reg = status_reg, | |
364 | }; | |
365 | ||
366 | /* cpu available? */ | |
367 | if (dst_cpu == NULL) { | |
368 | return SIGP_CC_NOT_OPERATIONAL; | |
369 | } | |
370 | ||
371 | /* only resets can break pending orders */ | |
372 | if (dst_cpu->env.sigp_order != 0 && | |
373 | order != SIGP_CPU_RESET && | |
374 | order != SIGP_INITIAL_CPU_RESET) { | |
375 | return SIGP_CC_BUSY; | |
376 | } | |
377 | ||
378 | switch (order) { | |
302230fc DH |
379 | case SIGP_SENSE: |
380 | sigp_sense(dst_cpu, &si); | |
381 | break; | |
070aa1a4 DH |
382 | case SIGP_EXTERNAL_CALL: |
383 | sigp_external_call(cpu, dst_cpu, &si); | |
384 | break; | |
c50105d4 DH |
385 | case SIGP_EMERGENCY: |
386 | sigp_emergency(cpu, dst_cpu, &si); | |
387 | break; | |
74b4c74d DH |
388 | case SIGP_START: |
389 | run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si)); | |
390 | break; | |
391 | case SIGP_STOP: | |
392 | run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si)); | |
393 | break; | |
394 | case SIGP_RESTART: | |
395 | run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si)); | |
396 | break; | |
397 | case SIGP_STOP_STORE_STATUS: | |
398 | run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si)); | |
399 | break; | |
400 | case SIGP_STORE_STATUS_ADDR: | |
401 | run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si)); | |
402 | break; | |
403 | case SIGP_STORE_ADTL_STATUS: | |
404 | run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si)); | |
405 | break; | |
406 | case SIGP_SET_PREFIX: | |
407 | run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si)); | |
408 | break; | |
409 | case SIGP_INITIAL_CPU_RESET: | |
410 | run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si)); | |
411 | break; | |
412 | case SIGP_CPU_RESET: | |
413 | run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si)); | |
414 | break; | |
a6880d21 DH |
415 | case SIGP_COND_EMERGENCY: |
416 | sigp_cond_emergency(cpu, dst_cpu, &si); | |
417 | break; | |
d1b468bc DH |
418 | case SIGP_SENSE_RUNNING: |
419 | sigp_sense_running(dst_cpu, &si); | |
420 | break; | |
74b4c74d DH |
421 | default: |
422 | set_sigp_status(&si, SIGP_STAT_INVALID_ORDER); | |
423 | } | |
424 | ||
425 | return si.cc; | |
426 | } | |
427 | ||
428 | static int sigp_set_architecture(S390CPU *cpu, uint32_t param, | |
429 | uint64_t *status_reg) | |
430 | { | |
74b4c74d DH |
431 | *status_reg &= 0xffffffff00000000ULL; |
432 | ||
433 | /* Reject set arch order, with czam we're always in z/Arch mode. */ | |
998eb744 | 434 | *status_reg |= SIGP_STAT_INVALID_PARAMETER; |
74b4c74d DH |
435 | return SIGP_CC_STATUS_STORED; |
436 | } | |
437 | ||
438 | int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3) | |
439 | { | |
440 | uint64_t *status_reg = &env->regs[r1]; | |
441 | uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1]; | |
dc79e928 | 442 | S390CPU *cpu = env_archcpu(env); |
74b4c74d DH |
443 | S390CPU *dst_cpu = NULL; |
444 | int ret; | |
445 | ||
446 | if (qemu_mutex_trylock(&qemu_sigp_mutex)) { | |
447 | ret = SIGP_CC_BUSY; | |
448 | goto out; | |
449 | } | |
450 | ||
451 | switch (order) { | |
452 | case SIGP_SET_ARCH: | |
453 | ret = sigp_set_architecture(cpu, param, status_reg); | |
454 | break; | |
455 | default: | |
456 | /* all other sigp orders target a single vcpu */ | |
457 | dst_cpu = s390_cpu_addr2state(env->regs[r3]); | |
070aa1a4 | 458 | ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg); |
74b4c74d DH |
459 | } |
460 | qemu_mutex_unlock(&qemu_sigp_mutex); | |
461 | ||
462 | out: | |
463 | trace_sigp_finished(order, CPU(cpu)->cpu_index, | |
464 | dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret); | |
465 | g_assert(ret >= 0); | |
466 | ||
467 | return ret; | |
468 | } | |
469 | ||
470 | int s390_cpu_restart(S390CPU *cpu) | |
471 | { | |
472 | SigpInfo si = {}; | |
473 | ||
74b4c74d DH |
474 | run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si)); |
475 | return 0; | |
476 | } | |
477 | ||
3047f8b5 DH |
478 | void do_stop_interrupt(CPUS390XState *env) |
479 | { | |
dc79e928 | 480 | S390CPU *cpu = env_archcpu(env); |
3047f8b5 | 481 | |
59b9b518 EF |
482 | /* |
483 | * Complete the STOP operation before exposing the CPU as | |
484 | * STOPPED to the system. | |
485 | */ | |
3047f8b5 DH |
486 | if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) { |
487 | s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true); | |
488 | } | |
489 | env->sigp_order = 0; | |
59b9b518 EF |
490 | if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) { |
491 | qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); | |
492 | } | |
b1ab5f60 | 493 | env->pending_int &= ~INTERRUPT_STOP; |
3047f8b5 DH |
494 | } |
495 | ||
74b4c74d DH |
496 | void s390_init_sigp(void) |
497 | { | |
498 | qemu_mutex_init(&qemu_sigp_mutex); | |
499 | } |