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" |
12 | #include "cpu.h" |
13 | #include "internal.h" |
14 | #include "sysemu/hw_accel.h" |
15 | #include "sysemu/runstate.h" |
16 | #include "exec/address-spaces.h" |
17 | #include "exec/exec-all.h" |
18 | #include "sysemu/tcg.h" |
19 | #include "trace.h" |
20 | #include "qapi/qapi-types-machine.h" |
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 | |
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 */ |
50 | if (state != S390_CPU_STATE_STOPPED && !ext_call) { |
51 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
52 | } else { |
53 | if (ext_call) { |
54 | status |= SIGP_STAT_EXT_CALL_PENDING; |
55 | } |
56 | if (state == S390_CPU_STATE_STOPPED) { |
57 | status |= SIGP_STAT_STOPPED; |
58 | } |
59 | set_sigp_status(si, status); |
60 | } |
61 | } |
62 | |
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 | |
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 | |
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 | |
98 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
99 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
100 | return; |
101 | } |
102 | |
103 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
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 | |
112 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) { |
113 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
114 | return; |
115 | } |
116 | |
117 | /* disabled wait - sleeping in user space */ |
118 | if (cs->halted) { |
119 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
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 */ |
134 | if (s390_cpu_get_state(cpu) == S390_CPU_STATE_OPERATING && cs->halted) { |
135 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
136 | } |
137 | |
138 | switch (s390_cpu_get_state(cpu)) { |
139 | case S390_CPU_STATE_OPERATING: |
140 | cpu->env.sigp_order = SIGP_STOP_STORE_STATUS; |
141 | cpu_inject_stop(cpu); |
142 | /* store will be performed in do_stop_interrup() */ |
143 | break; |
144 | case S390_CPU_STATE_STOPPED: |
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 */ |
160 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
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 */ |
190 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
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)) { |
233 | case S390_CPU_STATE_STOPPED: |
234 | /* the restart irq has to be delivered prior to any other pending irq */ |
235 | cpu_synchronize_state(cs); |
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 | */ |
240 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
241 | do_restart_interrupt(&cpu->env); |
242 | break; |
243 | case S390_CPU_STATE_OPERATING: |
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); |
257 | scc->initial_cpu_reset(cs); |
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); |
269 | scc->cpu_reset(cs); |
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, |
283 | sizeof(struct LowCore), false, |
284 | MEMTXATTRS_UNSPECIFIED)) { |
285 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
286 | return; |
287 | } |
288 | |
289 | /* cpu has to be stopped */ |
290 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
291 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
292 | return; |
293 | } |
294 | |
295 | cpu->env.psa = addr; |
296 | tlb_flush(cs); |
297 | cpu_synchronize_post_init(cs); |
298 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
299 | } |
300 | |
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 | |
323 | if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED || |
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 | |
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 | |
357 | static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order, |
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) { |
378 | case SIGP_SENSE: |
379 | sigp_sense(dst_cpu, &si); |
380 | break; |
381 | case SIGP_EXTERNAL_CALL: |
382 | sigp_external_call(cpu, dst_cpu, &si); |
383 | break; |
384 | case SIGP_EMERGENCY: |
385 | sigp_emergency(cpu, dst_cpu, &si); |
386 | break; |
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; |
414 | case SIGP_COND_EMERGENCY: |
415 | sigp_cond_emergency(cpu, dst_cpu, &si); |
416 | break; |
417 | case SIGP_SENSE_RUNNING: |
418 | sigp_sense_running(dst_cpu, &si); |
419 | break; |
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 | } |
440 | if (s390_cpu_get_state(cur_cpu) != S390_CPU_STATE_STOPPED) { |
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]; |
457 | S390CPU *cpu = env_archcpu(env); |
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]); |
473 | ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg); |
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 | |
489 | run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si)); |
490 | return 0; |
491 | } |
492 | |
493 | void do_stop_interrupt(CPUS390XState *env) |
494 | { |
495 | S390CPU *cpu = env_archcpu(env); |
496 | |
497 | if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) { |
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; |
504 | env->pending_int &= ~INTERRUPT_STOP; |
505 | } |
506 | |
507 | void s390_init_sigp(void) |
508 | { |
509 | qemu_mutex_init(&qemu_sigp_mutex); |
510 | } |
511 | |