]>
Commit | Line | Data |
---|---|---|
74b4c74d DH |
1 | /* |
2 | * s390x SIGP instruction handling | |
3 | * | |
4 | * Copyright (c) 2009 Alexander Graf <[email protected]> | |
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 DH |
12 | #include "cpu.h" |
13 | #include "internal.h" | |
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); | |
3047f8b5 | 142 | /* store will be performed in do_stop_interrup() */ |
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. | |
238 | * load_psw() will then properly halt the CPU again if necessary (TCG). | |
239 | */ | |
9d0306df | 240 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
741a4ec1 | 241 | do_restart_interrupt(&cpu->env); |
74b4c74d | 242 | break; |
9d0306df | 243 | case S390_CPU_STATE_OPERATING: |
74b4c74d DH |
244 | cpu_inject_restart(cpu); |
245 | break; | |
246 | } | |
247 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
248 | } | |
249 | ||
250 | static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg) | |
251 | { | |
252 | S390CPU *cpu = S390_CPU(cs); | |
253 | S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); | |
254 | SigpInfo *si = arg.host_ptr; | |
255 | ||
256 | cpu_synchronize_state(cs); | |
81b92223 | 257 | scc->reset(cs, S390_CPU_RESET_INITIAL); |
74b4c74d DH |
258 | cpu_synchronize_post_reset(cs); |
259 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
260 | } | |
261 | ||
262 | static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg) | |
263 | { | |
264 | S390CPU *cpu = S390_CPU(cs); | |
265 | S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); | |
266 | SigpInfo *si = arg.host_ptr; | |
267 | ||
268 | cpu_synchronize_state(cs); | |
eac4f827 | 269 | scc->reset(cs, S390_CPU_RESET_NORMAL); |
74b4c74d DH |
270 | cpu_synchronize_post_reset(cs); |
271 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
272 | } | |
273 | ||
274 | static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg) | |
275 | { | |
276 | S390CPU *cpu = S390_CPU(cs); | |
277 | SigpInfo *si = arg.host_ptr; | |
278 | uint32_t addr = si->param & 0x7fffe000u; | |
279 | ||
280 | cpu_synchronize_state(cs); | |
281 | ||
282 | if (!address_space_access_valid(&address_space_memory, addr, | |
fddffa42 PM |
283 | sizeof(struct LowCore), false, |
284 | MEMTXATTRS_UNSPECIFIED)) { | |
74b4c74d DH |
285 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
286 | return; | |
287 | } | |
288 | ||
289 | /* cpu has to be stopped */ | |
9d0306df | 290 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
74b4c74d DH |
291 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
292 | return; | |
293 | } | |
294 | ||
295 | cpu->env.psa = addr; | |
b376a554 | 296 | tlb_flush(cs); |
74b4c74d DH |
297 | cpu_synchronize_post_init(cs); |
298 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
299 | } | |
300 | ||
a6880d21 DH |
301 | static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, |
302 | SigpInfo *si) | |
303 | { | |
304 | const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT; | |
305 | uint16_t p_asn, s_asn, asn; | |
306 | uint64_t psw_addr, psw_mask; | |
307 | bool idle; | |
308 | ||
309 | if (!tcg_enabled()) { | |
310 | /* handled in KVM */ | |
311 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
312 | return; | |
313 | } | |
314 | ||
315 | /* this looks racy, but these values are only used when STOPPED */ | |
316 | idle = CPU(dst_cpu)->halted; | |
317 | psw_addr = dst_cpu->env.psw.addr; | |
318 | psw_mask = dst_cpu->env.psw.mask; | |
319 | asn = si->param; | |
320 | p_asn = dst_cpu->env.cregs[4] & 0xffff; /* Primary ASN */ | |
321 | s_asn = dst_cpu->env.cregs[3] & 0xffff; /* Secondary ASN */ | |
322 | ||
9d0306df | 323 | if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED || |
a6880d21 DH |
324 | (psw_mask & psw_int_mask) != psw_int_mask || |
325 | (idle && psw_addr != 0) || | |
326 | (!idle && (asn == p_asn || asn == s_asn))) { | |
327 | cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id); | |
328 | } else { | |
329 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); | |
330 | } | |
331 | ||
332 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
333 | } | |
334 | ||
d1b468bc DH |
335 | static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si) |
336 | { | |
337 | if (!tcg_enabled()) { | |
338 | /* handled in KVM */ | |
339 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
340 | return; | |
341 | } | |
342 | ||
343 | /* sensing without locks is racy, but it's the same for real hw */ | |
344 | if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) { | |
345 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); | |
346 | return; | |
347 | } | |
348 | ||
349 | /* If halted (which includes also STOPPED), it is not running */ | |
350 | if (CPU(dst_cpu)->halted) { | |
351 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; | |
352 | } else { | |
353 | set_sigp_status(si, SIGP_STAT_NOT_RUNNING); | |
354 | } | |
355 | } | |
356 | ||
070aa1a4 | 357 | static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order, |
74b4c74d DH |
358 | uint64_t param, uint64_t *status_reg) |
359 | { | |
360 | SigpInfo si = { | |
361 | .param = param, | |
362 | .status_reg = status_reg, | |
363 | }; | |
364 | ||
365 | /* cpu available? */ | |
366 | if (dst_cpu == NULL) { | |
367 | return SIGP_CC_NOT_OPERATIONAL; | |
368 | } | |
369 | ||
370 | /* only resets can break pending orders */ | |
371 | if (dst_cpu->env.sigp_order != 0 && | |
372 | order != SIGP_CPU_RESET && | |
373 | order != SIGP_INITIAL_CPU_RESET) { | |
374 | return SIGP_CC_BUSY; | |
375 | } | |
376 | ||
377 | switch (order) { | |
302230fc DH |
378 | case SIGP_SENSE: |
379 | sigp_sense(dst_cpu, &si); | |
380 | break; | |
070aa1a4 DH |
381 | case SIGP_EXTERNAL_CALL: |
382 | sigp_external_call(cpu, dst_cpu, &si); | |
383 | break; | |
c50105d4 DH |
384 | case SIGP_EMERGENCY: |
385 | sigp_emergency(cpu, dst_cpu, &si); | |
386 | break; | |
74b4c74d DH |
387 | case SIGP_START: |
388 | run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si)); | |
389 | break; | |
390 | case SIGP_STOP: | |
391 | run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si)); | |
392 | break; | |
393 | case SIGP_RESTART: | |
394 | run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si)); | |
395 | break; | |
396 | case SIGP_STOP_STORE_STATUS: | |
397 | run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si)); | |
398 | break; | |
399 | case SIGP_STORE_STATUS_ADDR: | |
400 | run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si)); | |
401 | break; | |
402 | case SIGP_STORE_ADTL_STATUS: | |
403 | run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si)); | |
404 | break; | |
405 | case SIGP_SET_PREFIX: | |
406 | run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si)); | |
407 | break; | |
408 | case SIGP_INITIAL_CPU_RESET: | |
409 | run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si)); | |
410 | break; | |
411 | case SIGP_CPU_RESET: | |
412 | run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si)); | |
413 | break; | |
a6880d21 DH |
414 | case SIGP_COND_EMERGENCY: |
415 | sigp_cond_emergency(cpu, dst_cpu, &si); | |
416 | break; | |
d1b468bc DH |
417 | case SIGP_SENSE_RUNNING: |
418 | sigp_sense_running(dst_cpu, &si); | |
419 | break; | |
74b4c74d DH |
420 | default: |
421 | set_sigp_status(&si, SIGP_STAT_INVALID_ORDER); | |
422 | } | |
423 | ||
424 | return si.cc; | |
425 | } | |
426 | ||
427 | static int sigp_set_architecture(S390CPU *cpu, uint32_t param, | |
428 | uint64_t *status_reg) | |
429 | { | |
430 | CPUState *cur_cs; | |
431 | S390CPU *cur_cpu; | |
432 | bool all_stopped = true; | |
433 | ||
434 | CPU_FOREACH(cur_cs) { | |
435 | cur_cpu = S390_CPU(cur_cs); | |
436 | ||
437 | if (cur_cpu == cpu) { | |
438 | continue; | |
439 | } | |
9d0306df | 440 | if (s390_cpu_get_state(cur_cpu) != S390_CPU_STATE_STOPPED) { |
74b4c74d DH |
441 | all_stopped = false; |
442 | } | |
443 | } | |
444 | ||
445 | *status_reg &= 0xffffffff00000000ULL; | |
446 | ||
447 | /* Reject set arch order, with czam we're always in z/Arch mode. */ | |
448 | *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER : | |
449 | SIGP_STAT_INCORRECT_STATE); | |
450 | return SIGP_CC_STATUS_STORED; | |
451 | } | |
452 | ||
453 | int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3) | |
454 | { | |
455 | uint64_t *status_reg = &env->regs[r1]; | |
456 | uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1]; | |
dc79e928 | 457 | S390CPU *cpu = env_archcpu(env); |
74b4c74d DH |
458 | S390CPU *dst_cpu = NULL; |
459 | int ret; | |
460 | ||
461 | if (qemu_mutex_trylock(&qemu_sigp_mutex)) { | |
462 | ret = SIGP_CC_BUSY; | |
463 | goto out; | |
464 | } | |
465 | ||
466 | switch (order) { | |
467 | case SIGP_SET_ARCH: | |
468 | ret = sigp_set_architecture(cpu, param, status_reg); | |
469 | break; | |
470 | default: | |
471 | /* all other sigp orders target a single vcpu */ | |
472 | dst_cpu = s390_cpu_addr2state(env->regs[r3]); | |
070aa1a4 | 473 | ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg); |
74b4c74d DH |
474 | } |
475 | qemu_mutex_unlock(&qemu_sigp_mutex); | |
476 | ||
477 | out: | |
478 | trace_sigp_finished(order, CPU(cpu)->cpu_index, | |
479 | dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret); | |
480 | g_assert(ret >= 0); | |
481 | ||
482 | return ret; | |
483 | } | |
484 | ||
485 | int s390_cpu_restart(S390CPU *cpu) | |
486 | { | |
487 | SigpInfo si = {}; | |
488 | ||
74b4c74d DH |
489 | run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si)); |
490 | return 0; | |
491 | } | |
492 | ||
3047f8b5 DH |
493 | void do_stop_interrupt(CPUS390XState *env) |
494 | { | |
dc79e928 | 495 | S390CPU *cpu = env_archcpu(env); |
3047f8b5 | 496 | |
9d0306df | 497 | if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) { |
3047f8b5 DH |
498 | qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); |
499 | } | |
500 | if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) { | |
501 | s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true); | |
502 | } | |
503 | env->sigp_order = 0; | |
b1ab5f60 | 504 | env->pending_int &= ~INTERRUPT_STOP; |
3047f8b5 DH |
505 | } |
506 | ||
74b4c74d DH |
507 | void s390_init_sigp(void) |
508 | { | |
509 | qemu_mutex_init(&qemu_sigp_mutex); | |
510 | } |