]> git.proxmox.com Git - mirror_qemu.git/blame - target/s390x/sigp.c
Merge remote-tracking branch 'remotes/hdeller/tags/hppa-updates-pull-request' into...
[mirror_qemu.git] / target / s390x / sigp.c
CommitLineData
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
22QemuMutex qemu_sigp_mutex;
23
24typedef struct SigpInfo {
25 uint64_t param;
26 int cc;
27 uint64_t *status_reg;
28} SigpInfo;
29
30static 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
37static 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
63static 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
81static 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
93static 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
107static 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
128static 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
153static 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
175static 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
227static 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
251static 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
263static 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
275static 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
302static 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
336static 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 358static 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
428static 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
438int 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
462out:
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
470int 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
478void 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
496void s390_init_sigp(void)
497{
498 qemu_mutex_init(&qemu_sigp_mutex);
499}