s390x/tcg: implement SIGP EMERGENCY SIGNAL
[qemu.git] / target / s390x / sigp.c
blobd492885787f08815246a5909c1d3789378b68fb7
1 /*
2 * s390x SIGP instruction handling
4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
5 * Copyright IBM Corp. 2012
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 */
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 "sysemu/sysemu.h"
18 #include "trace.h"
20 QemuMutex qemu_sigp_mutex;
22 typedef struct SigpInfo {
23 uint64_t param;
24 int cc;
25 uint64_t *status_reg;
26 } SigpInfo;
28 static void set_sigp_status(SigpInfo *si, uint64_t status)
30 *si->status_reg &= 0xffffffff00000000ULL;
31 *si->status_reg |= status;
32 si->cc = SIGP_CC_STATUS_STORED;
35 static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si)
37 uint8_t state = s390_cpu_get_state(dst_cpu);
38 bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL;
39 uint64_t status = 0;
41 if (!tcg_enabled()) {
42 /* handled in KVM */
43 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
44 return;
47 /* sensing without locks is racy, but it's the same for real hw */
48 if (state != CPU_STATE_STOPPED && !ext_call) {
49 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
50 } else {
51 if (ext_call) {
52 status |= SIGP_STAT_EXT_CALL_PENDING;
54 if (state == CPU_STATE_STOPPED) {
55 status |= SIGP_STAT_STOPPED;
57 set_sigp_status(si, status);
61 static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
63 int ret;
65 if (!tcg_enabled()) {
66 /* handled in KVM */
67 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
68 return;
71 ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id);
72 if (!ret) {
73 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
74 } else {
75 set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING);
79 static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
81 if (!tcg_enabled()) {
82 /* handled in KVM */
83 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
84 return;
87 cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
88 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
91 static void sigp_start(CPUState *cs, run_on_cpu_data arg)
93 S390CPU *cpu = S390_CPU(cs);
94 SigpInfo *si = arg.host_ptr;
96 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
97 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
98 return;
101 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
102 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
105 static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
107 S390CPU *cpu = S390_CPU(cs);
108 SigpInfo *si = arg.host_ptr;
110 if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING) {
111 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
112 return;
115 /* disabled wait - sleeping in user space */
116 if (cs->halted) {
117 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
118 } else {
119 /* execute the stop function */
120 cpu->env.sigp_order = SIGP_STOP;
121 cpu_inject_stop(cpu);
123 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
126 static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg)
128 S390CPU *cpu = S390_CPU(cs);
129 SigpInfo *si = arg.host_ptr;
131 /* disabled wait - sleeping in user space */
132 if (s390_cpu_get_state(cpu) == CPU_STATE_OPERATING && cs->halted) {
133 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
136 switch (s390_cpu_get_state(cpu)) {
137 case CPU_STATE_OPERATING:
138 cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
139 cpu_inject_stop(cpu);
140 /* store will be performed in do_stop_interrup() */
141 break;
142 case CPU_STATE_STOPPED:
143 /* already stopped, just store the status */
144 cpu_synchronize_state(cs);
145 s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
146 break;
148 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
151 static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
153 S390CPU *cpu = S390_CPU(cs);
154 SigpInfo *si = arg.host_ptr;
155 uint32_t address = si->param & 0x7ffffe00u;
157 /* cpu has to be stopped */
158 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
159 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
160 return;
163 cpu_synchronize_state(cs);
165 if (s390_store_status(cpu, address, false)) {
166 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
167 return;
169 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
172 #define ADTL_SAVE_LC_MASK 0xfUL
173 static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
175 S390CPU *cpu = S390_CPU(cs);
176 SigpInfo *si = arg.host_ptr;
177 uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
178 hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
179 hwaddr len = 1UL << (lc ? lc : 10);
181 if (!s390_has_feat(S390_FEAT_VECTOR) &&
182 !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
183 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
184 return;
187 /* cpu has to be stopped */
188 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
189 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
190 return;
193 /* address must be aligned to length */
194 if (addr & (len - 1)) {
195 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
196 return;
199 /* no GS: only lc == 0 is valid */
200 if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
201 lc != 0) {
202 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
203 return;
206 /* GS: 0, 10, 11, 12 are valid */
207 if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
208 lc != 0 &&
209 lc != 10 &&
210 lc != 11 &&
211 lc != 12) {
212 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
213 return;
216 cpu_synchronize_state(cs);
218 if (s390_store_adtl_status(cpu, addr, len)) {
219 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
220 return;
222 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
225 static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
227 S390CPU *cpu = S390_CPU(cs);
228 SigpInfo *si = arg.host_ptr;
230 switch (s390_cpu_get_state(cpu)) {
231 case CPU_STATE_STOPPED:
232 /* the restart irq has to be delivered prior to any other pending irq */
233 cpu_synchronize_state(cs);
234 do_restart_interrupt(&cpu->env);
235 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
236 break;
237 case CPU_STATE_OPERATING:
238 cpu_inject_restart(cpu);
239 break;
241 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
244 static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
246 S390CPU *cpu = S390_CPU(cs);
247 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
248 SigpInfo *si = arg.host_ptr;
250 cpu_synchronize_state(cs);
251 scc->initial_cpu_reset(cs);
252 cpu_synchronize_post_reset(cs);
253 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
256 static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
258 S390CPU *cpu = S390_CPU(cs);
259 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
260 SigpInfo *si = arg.host_ptr;
262 cpu_synchronize_state(cs);
263 scc->cpu_reset(cs);
264 cpu_synchronize_post_reset(cs);
265 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
268 static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
270 S390CPU *cpu = S390_CPU(cs);
271 SigpInfo *si = arg.host_ptr;
272 uint32_t addr = si->param & 0x7fffe000u;
274 cpu_synchronize_state(cs);
276 if (!address_space_access_valid(&address_space_memory, addr,
277 sizeof(struct LowCore), false)) {
278 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
279 return;
282 /* cpu has to be stopped */
283 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
284 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
285 return;
288 cpu->env.psa = addr;
289 cpu_synchronize_post_init(cs);
290 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
293 static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
295 if (!tcg_enabled()) {
296 /* handled in KVM */
297 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
298 return;
301 /* sensing without locks is racy, but it's the same for real hw */
302 if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
303 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
304 return;
307 /* If halted (which includes also STOPPED), it is not running */
308 if (CPU(dst_cpu)->halted) {
309 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
310 } else {
311 set_sigp_status(si, SIGP_STAT_NOT_RUNNING);
315 static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order,
316 uint64_t param, uint64_t *status_reg)
318 SigpInfo si = {
319 .param = param,
320 .status_reg = status_reg,
323 /* cpu available? */
324 if (dst_cpu == NULL) {
325 return SIGP_CC_NOT_OPERATIONAL;
328 /* only resets can break pending orders */
329 if (dst_cpu->env.sigp_order != 0 &&
330 order != SIGP_CPU_RESET &&
331 order != SIGP_INITIAL_CPU_RESET) {
332 return SIGP_CC_BUSY;
335 switch (order) {
336 case SIGP_SENSE:
337 sigp_sense(dst_cpu, &si);
338 break;
339 case SIGP_EXTERNAL_CALL:
340 sigp_external_call(cpu, dst_cpu, &si);
341 break;
342 case SIGP_EMERGENCY:
343 sigp_emergency(cpu, dst_cpu, &si);
344 break;
345 case SIGP_START:
346 run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
347 break;
348 case SIGP_STOP:
349 run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
350 break;
351 case SIGP_RESTART:
352 run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
353 break;
354 case SIGP_STOP_STORE_STATUS:
355 run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
356 break;
357 case SIGP_STORE_STATUS_ADDR:
358 run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
359 break;
360 case SIGP_STORE_ADTL_STATUS:
361 run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
362 break;
363 case SIGP_SET_PREFIX:
364 run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
365 break;
366 case SIGP_INITIAL_CPU_RESET:
367 run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
368 break;
369 case SIGP_CPU_RESET:
370 run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
371 break;
372 case SIGP_SENSE_RUNNING:
373 sigp_sense_running(dst_cpu, &si);
374 break;
375 default:
376 set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
379 return si.cc;
382 static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
383 uint64_t *status_reg)
385 CPUState *cur_cs;
386 S390CPU *cur_cpu;
387 bool all_stopped = true;
389 CPU_FOREACH(cur_cs) {
390 cur_cpu = S390_CPU(cur_cs);
392 if (cur_cpu == cpu) {
393 continue;
395 if (s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
396 all_stopped = false;
400 *status_reg &= 0xffffffff00000000ULL;
402 /* Reject set arch order, with czam we're always in z/Arch mode. */
403 *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
404 SIGP_STAT_INCORRECT_STATE);
405 return SIGP_CC_STATUS_STORED;
408 int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3)
410 uint64_t *status_reg = &env->regs[r1];
411 uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
412 S390CPU *cpu = s390_env_get_cpu(env);
413 S390CPU *dst_cpu = NULL;
414 int ret;
416 if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
417 ret = SIGP_CC_BUSY;
418 goto out;
421 switch (order) {
422 case SIGP_SET_ARCH:
423 ret = sigp_set_architecture(cpu, param, status_reg);
424 break;
425 default:
426 /* all other sigp orders target a single vcpu */
427 dst_cpu = s390_cpu_addr2state(env->regs[r3]);
428 ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg);
430 qemu_mutex_unlock(&qemu_sigp_mutex);
432 out:
433 trace_sigp_finished(order, CPU(cpu)->cpu_index,
434 dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
435 g_assert(ret >= 0);
437 return ret;
440 int s390_cpu_restart(S390CPU *cpu)
442 SigpInfo si = {};
444 if (tcg_enabled()) {
445 /* FIXME TCG */
446 return -ENOSYS;
449 run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
450 return 0;
453 void do_stop_interrupt(CPUS390XState *env)
455 S390CPU *cpu = s390_env_get_cpu(env);
457 if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
458 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
460 if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
461 s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
463 env->sigp_order = 0;
466 void s390_init_sigp(void)
468 qemu_mutex_init(&qemu_sigp_mutex);