1
2
3
4
5
6
7
8
9
10
11#include "qemu/osdep.h"
12#include "qemu-common.h"
13#include "cpu.h"
14#include "internal.h"
15#include "sysemu/hw_accel.h"
16#include "exec/address-spaces.h"
17#include "exec/exec-all.h"
18#include "sysemu/sysemu.h"
19#include "trace.h"
20
21QemuMutex qemu_sigp_mutex;
22
23typedef struct SigpInfo {
24 uint64_t param;
25 int cc;
26 uint64_t *status_reg;
27} SigpInfo;
28
29static void set_sigp_status(SigpInfo *si, uint64_t status)
30{
31 *si->status_reg &= 0xffffffff00000000ULL;
32 *si->status_reg |= status;
33 si->cc = SIGP_CC_STATUS_STORED;
34}
35
36static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si)
37{
38 uint8_t state = s390_cpu_get_state(dst_cpu);
39 bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL;
40 uint64_t status = 0;
41
42 if (!tcg_enabled()) {
43
44 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
45 return;
46 }
47
48
49 if (state != CPU_STATE_STOPPED && !ext_call) {
50 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
51 } else {
52 if (ext_call) {
53 status |= SIGP_STAT_EXT_CALL_PENDING;
54 }
55 if (state == CPU_STATE_STOPPED) {
56 status |= SIGP_STAT_STOPPED;
57 }
58 set_sigp_status(si, status);
59 }
60}
61
62static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
63{
64 int ret;
65
66 if (!tcg_enabled()) {
67
68 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
69 return;
70 }
71
72 ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id);
73 if (!ret) {
74 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
75 } else {
76 set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING);
77 }
78}
79
80static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
81{
82 if (!tcg_enabled()) {
83
84 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
85 return;
86 }
87
88 cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
89 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
90}
91
92static void sigp_start(CPUState *cs, run_on_cpu_data arg)
93{
94 S390CPU *cpu = S390_CPU(cs);
95 SigpInfo *si = arg.host_ptr;
96
97 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
98 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
99 return;
100 }
101
102 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
103 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
104}
105
106static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
107{
108 S390CPU *cpu = S390_CPU(cs);
109 SigpInfo *si = arg.host_ptr;
110
111 if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING) {
112 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
113 return;
114 }
115
116
117 if (cs->halted) {
118 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
119 } else {
120
121 cpu->env.sigp_order = SIGP_STOP;
122 cpu_inject_stop(cpu);
123 }
124 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
125}
126
127static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg)
128{
129 S390CPU *cpu = S390_CPU(cs);
130 SigpInfo *si = arg.host_ptr;
131
132
133 if (s390_cpu_get_state(cpu) == CPU_STATE_OPERATING && cs->halted) {
134 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
135 }
136
137 switch (s390_cpu_get_state(cpu)) {
138 case CPU_STATE_OPERATING:
139 cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
140 cpu_inject_stop(cpu);
141
142 break;
143 case CPU_STATE_STOPPED:
144
145 cpu_synchronize_state(cs);
146 s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
147 break;
148 }
149 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
150}
151
152static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
153{
154 S390CPU *cpu = S390_CPU(cs);
155 SigpInfo *si = arg.host_ptr;
156 uint32_t address = si->param & 0x7ffffe00u;
157
158
159 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
160 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
161 return;
162 }
163
164 cpu_synchronize_state(cs);
165
166 if (s390_store_status(cpu, address, false)) {
167 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
168 return;
169 }
170 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
171}
172
173#define ADTL_SAVE_LC_MASK 0xfUL
174static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
175{
176 S390CPU *cpu = S390_CPU(cs);
177 SigpInfo *si = arg.host_ptr;
178 uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
179 hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
180 hwaddr len = 1UL << (lc ? lc : 10);
181
182 if (!s390_has_feat(S390_FEAT_VECTOR) &&
183 !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
184 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
185 return;
186 }
187
188
189 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
190 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
191 return;
192 }
193
194
195 if (addr & (len - 1)) {
196 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
197 return;
198 }
199
200
201 if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
202 lc != 0) {
203 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
204 return;
205 }
206
207
208 if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
209 lc != 0 &&
210 lc != 10 &&
211 lc != 11 &&
212 lc != 12) {
213 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
214 return;
215 }
216
217 cpu_synchronize_state(cs);
218
219 if (s390_store_adtl_status(cpu, addr, len)) {
220 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
221 return;
222 }
223 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
224}
225
226static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
227{
228 S390CPU *cpu = S390_CPU(cs);
229 SigpInfo *si = arg.host_ptr;
230
231 switch (s390_cpu_get_state(cpu)) {
232 case CPU_STATE_STOPPED:
233
234 cpu_synchronize_state(cs);
235
236
237
238
239 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
240 do_restart_interrupt(&cpu->env);
241 break;
242 case CPU_STATE_OPERATING:
243 cpu_inject_restart(cpu);
244 break;
245 }
246 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
247}
248
249static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
250{
251 S390CPU *cpu = S390_CPU(cs);
252 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
253 SigpInfo *si = arg.host_ptr;
254
255 cpu_synchronize_state(cs);
256 scc->initial_cpu_reset(cs);
257 cpu_synchronize_post_reset(cs);
258 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
259}
260
261static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
262{
263 S390CPU *cpu = S390_CPU(cs);
264 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
265 SigpInfo *si = arg.host_ptr;
266
267 cpu_synchronize_state(cs);
268 scc->cpu_reset(cs);
269 cpu_synchronize_post_reset(cs);
270 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
271}
272
273static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
274{
275 S390CPU *cpu = S390_CPU(cs);
276 SigpInfo *si = arg.host_ptr;
277 uint32_t addr = si->param & 0x7fffe000u;
278
279 cpu_synchronize_state(cs);
280
281 if (!address_space_access_valid(&address_space_memory, addr,
282 sizeof(struct LowCore), false)) {
283 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
284 return;
285 }
286
287
288 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
289 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
290 return;
291 }
292
293 cpu->env.psa = addr;
294 tlb_flush(cs);
295 cpu_synchronize_post_init(cs);
296 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
297}
298
299static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu,
300 SigpInfo *si)
301{
302 const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
303 uint16_t p_asn, s_asn, asn;
304 uint64_t psw_addr, psw_mask;
305 bool idle;
306
307 if (!tcg_enabled()) {
308
309 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
310 return;
311 }
312
313
314 idle = CPU(dst_cpu)->halted;
315 psw_addr = dst_cpu->env.psw.addr;
316 psw_mask = dst_cpu->env.psw.mask;
317 asn = si->param;
318 p_asn = dst_cpu->env.cregs[4] & 0xffff;
319 s_asn = dst_cpu->env.cregs[3] & 0xffff;
320
321 if (s390_cpu_get_state(dst_cpu) != CPU_STATE_STOPPED ||
322 (psw_mask & psw_int_mask) != psw_int_mask ||
323 (idle && psw_addr != 0) ||
324 (!idle && (asn == p_asn || asn == s_asn))) {
325 cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
326 } else {
327 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
328 }
329
330 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
331}
332
333static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
334{
335 if (!tcg_enabled()) {
336
337 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
338 return;
339 }
340
341
342 if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
343 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
344 return;
345 }
346
347
348 if (CPU(dst_cpu)->halted) {
349 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
350 } else {
351 set_sigp_status(si, SIGP_STAT_NOT_RUNNING);
352 }
353}
354
355static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order,
356 uint64_t param, uint64_t *status_reg)
357{
358 SigpInfo si = {
359 .param = param,
360 .status_reg = status_reg,
361 };
362
363
364 if (dst_cpu == NULL) {
365 return SIGP_CC_NOT_OPERATIONAL;
366 }
367
368
369 if (dst_cpu->env.sigp_order != 0 &&
370 order != SIGP_CPU_RESET &&
371 order != SIGP_INITIAL_CPU_RESET) {
372 return SIGP_CC_BUSY;
373 }
374
375 switch (order) {
376 case SIGP_SENSE:
377 sigp_sense(dst_cpu, &si);
378 break;
379 case SIGP_EXTERNAL_CALL:
380 sigp_external_call(cpu, dst_cpu, &si);
381 break;
382 case SIGP_EMERGENCY:
383 sigp_emergency(cpu, dst_cpu, &si);
384 break;
385 case SIGP_START:
386 run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
387 break;
388 case SIGP_STOP:
389 run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
390 break;
391 case SIGP_RESTART:
392 run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
393 break;
394 case SIGP_STOP_STORE_STATUS:
395 run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
396 break;
397 case SIGP_STORE_STATUS_ADDR:
398 run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
399 break;
400 case SIGP_STORE_ADTL_STATUS:
401 run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
402 break;
403 case SIGP_SET_PREFIX:
404 run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
405 break;
406 case SIGP_INITIAL_CPU_RESET:
407 run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
408 break;
409 case SIGP_CPU_RESET:
410 run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
411 break;
412 case SIGP_COND_EMERGENCY:
413 sigp_cond_emergency(cpu, dst_cpu, &si);
414 break;
415 case SIGP_SENSE_RUNNING:
416 sigp_sense_running(dst_cpu, &si);
417 break;
418 default:
419 set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
420 }
421
422 return si.cc;
423}
424
425static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
426 uint64_t *status_reg)
427{
428 CPUState *cur_cs;
429 S390CPU *cur_cpu;
430 bool all_stopped = true;
431
432 CPU_FOREACH(cur_cs) {
433 cur_cpu = S390_CPU(cur_cs);
434
435 if (cur_cpu == cpu) {
436 continue;
437 }
438 if (s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
439 all_stopped = false;
440 }
441 }
442
443 *status_reg &= 0xffffffff00000000ULL;
444
445
446 *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
447 SIGP_STAT_INCORRECT_STATE);
448 return SIGP_CC_STATUS_STORED;
449}
450
451int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3)
452{
453 uint64_t *status_reg = &env->regs[r1];
454 uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
455 S390CPU *cpu = s390_env_get_cpu(env);
456 S390CPU *dst_cpu = NULL;
457 int ret;
458
459 if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
460 ret = SIGP_CC_BUSY;
461 goto out;
462 }
463
464 switch (order) {
465 case SIGP_SET_ARCH:
466 ret = sigp_set_architecture(cpu, param, status_reg);
467 break;
468 default:
469
470 dst_cpu = s390_cpu_addr2state(env->regs[r3]);
471 ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg);
472 }
473 qemu_mutex_unlock(&qemu_sigp_mutex);
474
475out:
476 trace_sigp_finished(order, CPU(cpu)->cpu_index,
477 dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
478 g_assert(ret >= 0);
479
480 return ret;
481}
482
483int s390_cpu_restart(S390CPU *cpu)
484{
485 SigpInfo si = {};
486
487 run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
488 return 0;
489}
490
491void do_stop_interrupt(CPUS390XState *env)
492{
493 S390CPU *cpu = s390_env_get_cpu(env);
494
495 if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
496 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
497 }
498 if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
499 s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
500 }
501 env->sigp_order = 0;
502 env->pending_int &= ~INTERRUPT_STOP;
503}
504
505void s390_init_sigp(void)
506{
507 qemu_mutex_init(&qemu_sigp_mutex);
508}
509