xref: /openbmc/linux/arch/s390/kvm/sigp.c (revision cada938a)
1d809aa23SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
25288fbf0SChristian Borntraeger /*
3a53c8fabSHeiko Carstens  * handling interprocessor communication
45288fbf0SChristian Borntraeger  *
5b13d3580SThomas Huth  * Copyright IBM Corp. 2008, 2013
65288fbf0SChristian Borntraeger  *
75288fbf0SChristian Borntraeger  *    Author(s): Carsten Otte <cotte@de.ibm.com>
85288fbf0SChristian Borntraeger  *               Christian Borntraeger <borntraeger@de.ibm.com>
99ace903dSChristian Ehrhardt  *               Christian Ehrhardt <ehrhardt@de.ibm.com>
105288fbf0SChristian Borntraeger  */
115288fbf0SChristian Borntraeger 
125288fbf0SChristian Borntraeger #include <linux/kvm.h>
135288fbf0SChristian Borntraeger #include <linux/kvm_host.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
15a9ae32c3SHeiko Carstens #include <asm/sigp.h>
165288fbf0SChristian Borntraeger #include "gaccess.h"
175288fbf0SChristian Borntraeger #include "kvm-s390.h"
185786fffaSCornelia Huck #include "trace.h"
195288fbf0SChristian Borntraeger 
__sigp_sense(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u64 * reg)203d95c7d2SDavid Hildenbrand static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
215a32c1afSChristian Borntraeger 			u64 *reg)
225288fbf0SChristian Borntraeger {
238d5fb0dcSDavid Hildenbrand 	const bool stopped = kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_STOPPED);
245288fbf0SChristian Borntraeger 	int rc;
25ea5f4969SDavid Hildenbrand 	int ext_call_pending;
265288fbf0SChristian Borntraeger 
27ea5f4969SDavid Hildenbrand 	ext_call_pending = kvm_s390_ext_call_pending(dst_vcpu);
288d5fb0dcSDavid Hildenbrand 	if (!stopped && !ext_call_pending)
2921b26c08SCornelia Huck 		rc = SIGP_CC_ORDER_CODE_ACCEPTED;
3021b26c08SCornelia Huck 	else {
315288fbf0SChristian Borntraeger 		*reg &= 0xffffffff00000000UL;
32ea5f4969SDavid Hildenbrand 		if (ext_call_pending)
3321b26c08SCornelia Huck 			*reg |= SIGP_STATUS_EXT_CALL_PENDING;
348d5fb0dcSDavid Hildenbrand 		if (stopped)
35a9ae32c3SHeiko Carstens 			*reg |= SIGP_STATUS_STOPPED;
36ea1918ddSHeiko Carstens 		rc = SIGP_CC_STATUS_STORED;
375288fbf0SChristian Borntraeger 	}
385288fbf0SChristian Borntraeger 
393d95c7d2SDavid Hildenbrand 	VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", dst_vcpu->vcpu_id,
403d95c7d2SDavid Hildenbrand 		   rc);
415288fbf0SChristian Borntraeger 	return rc;
425288fbf0SChristian Borntraeger }
435288fbf0SChristian Borntraeger 
__inject_sigp_emergency(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu)4407b03035SDavid Hildenbrand static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
4507b03035SDavid Hildenbrand 				    struct kvm_vcpu *dst_vcpu)
465288fbf0SChristian Borntraeger {
47383d0b05SJens Freimann 	struct kvm_s390_irq irq = {
4822ff4a33SJens Freimann 		.type = KVM_S390_INT_EMERGENCY,
49383d0b05SJens Freimann 		.u.emerg.code = vcpu->vcpu_id,
5022ff4a33SJens Freimann 	};
5122ff4a33SJens Freimann 	int rc = 0;
525288fbf0SChristian Borntraeger 
53383d0b05SJens Freimann 	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
5422ff4a33SJens Freimann 	if (!rc)
553d95c7d2SDavid Hildenbrand 		VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
563d95c7d2SDavid Hildenbrand 			   dst_vcpu->vcpu_id);
571ee0bc55SJens Freimann 
5822ff4a33SJens Freimann 	return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
597697e71fSChristian Ehrhardt }
607697e71fSChristian Ehrhardt 
__sigp_emergency(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu)6107b03035SDavid Hildenbrand static int __sigp_emergency(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu)
6207b03035SDavid Hildenbrand {
6307b03035SDavid Hildenbrand 	return __inject_sigp_emergency(vcpu, dst_vcpu);
6407b03035SDavid Hildenbrand }
6507b03035SDavid Hildenbrand 
__sigp_conditional_emergency(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u16 asn,u64 * reg)663d95c7d2SDavid Hildenbrand static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
673d95c7d2SDavid Hildenbrand 					struct kvm_vcpu *dst_vcpu,
68b13d3580SThomas Huth 					u16 asn, u64 *reg)
69b13d3580SThomas Huth {
70b13d3580SThomas Huth 	const u64 psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
71b13d3580SThomas Huth 	u16 p_asn, s_asn;
72b13d3580SThomas Huth 	psw_t *psw;
7394a15de8SDavid Hildenbrand 	bool idle;
74b13d3580SThomas Huth 
7594a15de8SDavid Hildenbrand 	idle = is_vcpu_idle(vcpu);
76b13d3580SThomas Huth 	psw = &dst_vcpu->arch.sie_block->gpsw;
77b13d3580SThomas Huth 	p_asn = dst_vcpu->arch.sie_block->gcr[4] & 0xffff;  /* Primary ASN */
78b13d3580SThomas Huth 	s_asn = dst_vcpu->arch.sie_block->gcr[3] & 0xffff;  /* Secondary ASN */
79b13d3580SThomas Huth 
8007b03035SDavid Hildenbrand 	/* Inject the emergency signal? */
8194a15de8SDavid Hildenbrand 	if (!is_vcpu_stopped(vcpu)
82b13d3580SThomas Huth 	    || (psw->mask & psw_int_mask) != psw_int_mask
8394a15de8SDavid Hildenbrand 	    || (idle && psw->addr != 0)
8494a15de8SDavid Hildenbrand 	    || (!idle && (asn == p_asn || asn == s_asn))) {
8507b03035SDavid Hildenbrand 		return __inject_sigp_emergency(vcpu, dst_vcpu);
86b13d3580SThomas Huth 	} else {
87b13d3580SThomas Huth 		*reg &= 0xffffffff00000000UL;
88b13d3580SThomas Huth 		*reg |= SIGP_STATUS_INCORRECT_STATE;
89b13d3580SThomas Huth 		return SIGP_CC_STATUS_STORED;
90b13d3580SThomas Huth 	}
91b13d3580SThomas Huth }
92b13d3580SThomas Huth 
__sigp_external_call(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u64 * reg)933d95c7d2SDavid Hildenbrand static int __sigp_external_call(struct kvm_vcpu *vcpu,
94ea5f4969SDavid Hildenbrand 				struct kvm_vcpu *dst_vcpu, u64 *reg)
957697e71fSChristian Ehrhardt {
96383d0b05SJens Freimann 	struct kvm_s390_irq irq = {
9722ff4a33SJens Freimann 		.type = KVM_S390_INT_EXTERNAL_CALL,
98383d0b05SJens Freimann 		.u.extcall.code = vcpu->vcpu_id,
9922ff4a33SJens Freimann 	};
10022ff4a33SJens Freimann 	int rc;
1017697e71fSChristian Ehrhardt 
102383d0b05SJens Freimann 	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
103ea5f4969SDavid Hildenbrand 	if (rc == -EBUSY) {
104ea5f4969SDavid Hildenbrand 		*reg &= 0xffffffff00000000UL;
105ea5f4969SDavid Hildenbrand 		*reg |= SIGP_STATUS_EXT_CALL_PENDING;
106ea5f4969SDavid Hildenbrand 		return SIGP_CC_STATUS_STORED;
107ea5f4969SDavid Hildenbrand 	} else if (rc == 0) {
1083d95c7d2SDavid Hildenbrand 		VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
1093d95c7d2SDavid Hildenbrand 			   dst_vcpu->vcpu_id);
110ea5f4969SDavid Hildenbrand 	}
1111ee0bc55SJens Freimann 
11222ff4a33SJens Freimann 	return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
1135288fbf0SChristian Borntraeger }
1145288fbf0SChristian Borntraeger 
__sigp_stop(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu)115a6cc3108SDavid Hildenbrand static int __sigp_stop(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu)
1165288fbf0SChristian Borntraeger {
1176cddd432SDavid Hildenbrand 	struct kvm_s390_irq irq = {
1186cddd432SDavid Hildenbrand 		.type = KVM_S390_SIGP_STOP,
1196cddd432SDavid Hildenbrand 	};
1205288fbf0SChristian Borntraeger 	int rc;
1215288fbf0SChristian Borntraeger 
1226cddd432SDavid Hildenbrand 	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
1236cddd432SDavid Hildenbrand 	if (rc == -EBUSY)
1246cddd432SDavid Hildenbrand 		rc = SIGP_CC_BUSY;
1256cddd432SDavid Hildenbrand 	else if (rc == 0)
1266cddd432SDavid Hildenbrand 		VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x",
1276cddd432SDavid Hildenbrand 			   dst_vcpu->vcpu_id);
128e879892cSThomas Huth 
129a6cc3108SDavid Hildenbrand 	return rc;
130a6cc3108SDavid Hildenbrand }
131a6cc3108SDavid Hildenbrand 
__sigp_stop_and_store_status(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u64 * reg)132a6cc3108SDavid Hildenbrand static int __sigp_stop_and_store_status(struct kvm_vcpu *vcpu,
133a6cc3108SDavid Hildenbrand 					struct kvm_vcpu *dst_vcpu, u64 *reg)
134a6cc3108SDavid Hildenbrand {
1356cddd432SDavid Hildenbrand 	struct kvm_s390_irq irq = {
1366cddd432SDavid Hildenbrand 		.type = KVM_S390_SIGP_STOP,
1376cddd432SDavid Hildenbrand 		.u.stop.flags = KVM_S390_STOP_FLAG_STORE_STATUS,
1386cddd432SDavid Hildenbrand 	};
139a6cc3108SDavid Hildenbrand 	int rc;
140a6cc3108SDavid Hildenbrand 
1416cddd432SDavid Hildenbrand 	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
1426cddd432SDavid Hildenbrand 	if (rc == -EBUSY)
1436cddd432SDavid Hildenbrand 		rc = SIGP_CC_BUSY;
1446cddd432SDavid Hildenbrand 	else if (rc == 0)
145a6cc3108SDavid Hildenbrand 		VCPU_EVENT(vcpu, 4, "sent sigp stop and store status to cpu %x",
146a6cc3108SDavid Hildenbrand 			   dst_vcpu->vcpu_id);
147a6cc3108SDavid Hildenbrand 
1485288fbf0SChristian Borntraeger 	return rc;
1495288fbf0SChristian Borntraeger }
1505288fbf0SChristian Borntraeger 
__sigp_set_arch(struct kvm_vcpu * vcpu,u32 parameter,u64 * status_reg)151b697e435SJason J. Herne static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter,
152b697e435SJason J. Herne 			   u64 *status_reg)
1535288fbf0SChristian Borntraeger {
154b697e435SJason J. Herne 	*status_reg &= 0xffffffff00000000UL;
155b697e435SJason J. Herne 
156b697e435SJason J. Herne 	/* Reject set arch order, with czam we're always in z/Arch mode. */
1578eeba194SEric Farman 	*status_reg |= SIGP_STATUS_INVALID_PARAMETER;
158b697e435SJason J. Herne 	return SIGP_CC_STATUS_STORED;
1595288fbf0SChristian Borntraeger }
1605288fbf0SChristian Borntraeger 
__sigp_set_prefix(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u32 address,u64 * reg)1613d95c7d2SDavid Hildenbrand static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
1623d95c7d2SDavid Hildenbrand 			     u32 address, u64 *reg)
1635288fbf0SChristian Borntraeger {
164a3a9c59aSDavid Hildenbrand 	struct kvm_s390_irq irq = {
165a3a9c59aSDavid Hildenbrand 		.type = KVM_S390_SIGP_SET_PREFIX,
166a3a9c59aSDavid Hildenbrand 		.u.prefix.address = address & 0x7fffe000u,
167a3a9c59aSDavid Hildenbrand 	};
1685288fbf0SChristian Borntraeger 	int rc;
1695288fbf0SChristian Borntraeger 
170665170cbSHeiko Carstens 	/*
171665170cbSHeiko Carstens 	 * Make sure the new value is valid memory. We only need to check the
172665170cbSHeiko Carstens 	 * first page, since address is 8k aligned and memory pieces are always
173665170cbSHeiko Carstens 	 * at least 1MB aligned and have at least a size of 1MB.
174665170cbSHeiko Carstens 	 */
175a3a9c59aSDavid Hildenbrand 	if (kvm_is_error_gpa(vcpu->kvm, irq.u.prefix.address)) {
1760744426eSHeiko Carstens 		*reg &= 0xffffffff00000000UL;
177a9ae32c3SHeiko Carstens 		*reg |= SIGP_STATUS_INVALID_PARAMETER;
178ea1918ddSHeiko Carstens 		return SIGP_CC_STATUS_STORED;
1795288fbf0SChristian Borntraeger 	}
1805288fbf0SChristian Borntraeger 
181a3a9c59aSDavid Hildenbrand 	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
182a3a9c59aSDavid Hildenbrand 	if (rc == -EBUSY) {
1830744426eSHeiko Carstens 		*reg &= 0xffffffff00000000UL;
1840744426eSHeiko Carstens 		*reg |= SIGP_STATUS_INCORRECT_STATE;
185a3a9c59aSDavid Hildenbrand 		return SIGP_CC_STATUS_STORED;
1865288fbf0SChristian Borntraeger 	}
1875288fbf0SChristian Borntraeger 
1885288fbf0SChristian Borntraeger 	return rc;
1895288fbf0SChristian Borntraeger }
1905288fbf0SChristian Borntraeger 
__sigp_store_status_at_addr(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u32 addr,u64 * reg)1913d95c7d2SDavid Hildenbrand static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu,
1923d95c7d2SDavid Hildenbrand 				       struct kvm_vcpu *dst_vcpu,
19300e9e435SThomas Huth 				       u32 addr, u64 *reg)
19400e9e435SThomas Huth {
19500e9e435SThomas Huth 	int rc;
19600e9e435SThomas Huth 
1978d5fb0dcSDavid Hildenbrand 	if (!kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_STOPPED)) {
19800e9e435SThomas Huth 		*reg &= 0xffffffff00000000UL;
19900e9e435SThomas Huth 		*reg |= SIGP_STATUS_INCORRECT_STATE;
20000e9e435SThomas Huth 		return SIGP_CC_STATUS_STORED;
20100e9e435SThomas Huth 	}
20200e9e435SThomas Huth 
20300e9e435SThomas Huth 	addr &= 0x7ffffe00;
20400e9e435SThomas Huth 	rc = kvm_s390_store_status_unloaded(dst_vcpu, addr);
20500e9e435SThomas Huth 	if (rc == -EFAULT) {
20600e9e435SThomas Huth 		*reg &= 0xffffffff00000000UL;
20700e9e435SThomas Huth 		*reg |= SIGP_STATUS_INVALID_PARAMETER;
20800e9e435SThomas Huth 		rc = SIGP_CC_STATUS_STORED;
20900e9e435SThomas Huth 	}
21000e9e435SThomas Huth 	return rc;
21100e9e435SThomas Huth }
21200e9e435SThomas Huth 
__sigp_sense_running(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u64 * reg)2133d95c7d2SDavid Hildenbrand static int __sigp_sense_running(struct kvm_vcpu *vcpu,
2143d95c7d2SDavid Hildenbrand 				struct kvm_vcpu *dst_vcpu, u64 *reg)
215bd59d3a4SCornelia Huck {
216bd59d3a4SCornelia Huck 	int rc;
217bd59d3a4SCornelia Huck 
218bd50e8ecSDavid Hildenbrand 	if (!test_kvm_facility(vcpu->kvm, 9)) {
219bd50e8ecSDavid Hildenbrand 		*reg &= 0xffffffff00000000UL;
220bd50e8ecSDavid Hildenbrand 		*reg |= SIGP_STATUS_INVALID_ORDER;
221bd50e8ecSDavid Hildenbrand 		return SIGP_CC_STATUS_STORED;
222bd50e8ecSDavid Hildenbrand 	}
223bd50e8ecSDavid Hildenbrand 
2248d5fb0dcSDavid Hildenbrand 	if (kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_RUNNING)) {
225bd59d3a4SCornelia Huck 		/* running */
226ea1918ddSHeiko Carstens 		rc = SIGP_CC_ORDER_CODE_ACCEPTED;
227bd59d3a4SCornelia Huck 	} else {
228bd59d3a4SCornelia Huck 		/* not running */
229bd59d3a4SCornelia Huck 		*reg &= 0xffffffff00000000UL;
230a9ae32c3SHeiko Carstens 		*reg |= SIGP_STATUS_NOT_RUNNING;
231ea1918ddSHeiko Carstens 		rc = SIGP_CC_STATUS_STORED;
232bd59d3a4SCornelia Huck 	}
233bd59d3a4SCornelia Huck 
2343d95c7d2SDavid Hildenbrand 	VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x",
2353d95c7d2SDavid Hildenbrand 		   dst_vcpu->vcpu_id, rc);
236bd59d3a4SCornelia Huck 
237bd59d3a4SCornelia Huck 	return rc;
238bd59d3a4SCornelia Huck }
239bd59d3a4SCornelia Huck 
__prepare_sigp_re_start(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u8 order_code)240b8983830SDavid Hildenbrand static int __prepare_sigp_re_start(struct kvm_vcpu *vcpu,
241b8983830SDavid Hildenbrand 				   struct kvm_vcpu *dst_vcpu, u8 order_code)
242151104a7SJens Freimann {
2433d95c7d2SDavid Hildenbrand 	struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
244b8983830SDavid Hildenbrand 	/* handle (RE)START in user space */
245b8983830SDavid Hildenbrand 	int rc = -EOPNOTSUPP;
246151104a7SJens Freimann 
2476cddd432SDavid Hildenbrand 	/* make sure we don't race with STOP irq injection */
2484ae3c081SDavid Hildenbrand 	spin_lock(&li->lock);
2496cddd432SDavid Hildenbrand 	if (kvm_s390_is_stop_irq_pending(dst_vcpu))
250ea1918ddSHeiko Carstens 		rc = SIGP_CC_BUSY;
2514ae3c081SDavid Hildenbrand 	spin_unlock(&li->lock);
2521ee0bc55SJens Freimann 
253151104a7SJens Freimann 	return rc;
254151104a7SJens Freimann }
255151104a7SJens Freimann 
__prepare_sigp_cpu_reset(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu,u8 order_code)256b8983830SDavid Hildenbrand static int __prepare_sigp_cpu_reset(struct kvm_vcpu *vcpu,
257b8983830SDavid Hildenbrand 				    struct kvm_vcpu *dst_vcpu, u8 order_code)
258b8983830SDavid Hildenbrand {
259b8983830SDavid Hildenbrand 	/* handle (INITIAL) CPU RESET in user space */
260b8983830SDavid Hildenbrand 	return -EOPNOTSUPP;
261b8983830SDavid Hildenbrand }
262b8983830SDavid Hildenbrand 
__prepare_sigp_unknown(struct kvm_vcpu * vcpu,struct kvm_vcpu * dst_vcpu)263b8983830SDavid Hildenbrand static int __prepare_sigp_unknown(struct kvm_vcpu *vcpu,
264b8983830SDavid Hildenbrand 				  struct kvm_vcpu *dst_vcpu)
265b8983830SDavid Hildenbrand {
266b8983830SDavid Hildenbrand 	/* handle unknown orders in user space */
267b8983830SDavid Hildenbrand 	return -EOPNOTSUPP;
268b8983830SDavid Hildenbrand }
269b8983830SDavid Hildenbrand 
handle_sigp_dst(struct kvm_vcpu * vcpu,u8 order_code,u16 cpu_addr,u32 parameter,u64 * status_reg)2703526a66bSDavid Hildenbrand static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,
2713526a66bSDavid Hildenbrand 			   u16 cpu_addr, u32 parameter, u64 *status_reg)
2723526a66bSDavid Hildenbrand {
2733526a66bSDavid Hildenbrand 	int rc;
274152e9f65SDavid Hildenbrand 	struct kvm_vcpu *dst_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
2753d95c7d2SDavid Hildenbrand 
2763d95c7d2SDavid Hildenbrand 	if (!dst_vcpu)
2773d95c7d2SDavid Hildenbrand 		return SIGP_CC_NOT_OPERATIONAL;
2783526a66bSDavid Hildenbrand 
279812de046SEric Farman 	/*
280812de046SEric Farman 	 * SIGP RESTART, SIGP STOP, and SIGP STOP AND STORE STATUS orders
281812de046SEric Farman 	 * are processed asynchronously. Until the affected VCPU finishes
282812de046SEric Farman 	 * its work and calls back into KVM to clear the (RESTART or STOP)
283812de046SEric Farman 	 * interrupt, we need to return any new non-reset orders "busy".
284812de046SEric Farman 	 *
285812de046SEric Farman 	 * This is important because a single VCPU could issue:
286812de046SEric Farman 	 *  1) SIGP STOP $DESTINATION
287812de046SEric Farman 	 *  2) SIGP SENSE $DESTINATION
288812de046SEric Farman 	 *
289812de046SEric Farman 	 * If the SIGP SENSE would not be rejected as "busy", it could
290812de046SEric Farman 	 * return an incorrect answer as to whether the VCPU is STOPPED
291812de046SEric Farman 	 * or OPERATING.
292812de046SEric Farman 	 */
293812de046SEric Farman 	if (order_code != SIGP_INITIAL_CPU_RESET &&
294812de046SEric Farman 	    order_code != SIGP_CPU_RESET) {
295812de046SEric Farman 		/*
296812de046SEric Farman 		 * Lockless check. Both SIGP STOP and SIGP (RE)START
297812de046SEric Farman 		 * properly synchronize everything while processing
298812de046SEric Farman 		 * their orders, while the guest cannot observe a
299812de046SEric Farman 		 * difference when issuing other orders from two
300812de046SEric Farman 		 * different VCPUs.
301812de046SEric Farman 		 */
302812de046SEric Farman 		if (kvm_s390_is_stop_irq_pending(dst_vcpu) ||
303812de046SEric Farman 		    kvm_s390_is_restart_irq_pending(dst_vcpu))
304812de046SEric Farman 			return SIGP_CC_BUSY;
305812de046SEric Farman 	}
306812de046SEric Farman 
3073526a66bSDavid Hildenbrand 	switch (order_code) {
3083526a66bSDavid Hildenbrand 	case SIGP_SENSE:
3093526a66bSDavid Hildenbrand 		vcpu->stat.instruction_sigp_sense++;
3103d95c7d2SDavid Hildenbrand 		rc = __sigp_sense(vcpu, dst_vcpu, status_reg);
3113526a66bSDavid Hildenbrand 		break;
3123526a66bSDavid Hildenbrand 	case SIGP_EXTERNAL_CALL:
3133526a66bSDavid Hildenbrand 		vcpu->stat.instruction_sigp_external_call++;
314ea5f4969SDavid Hildenbrand 		rc = __sigp_external_call(vcpu, dst_vcpu, status_reg);
3153526a66bSDavid Hildenbrand 		break;
3163526a66bSDavid Hildenbrand 	case SIGP_EMERGENCY_SIGNAL:
3173526a66bSDavid Hildenbrand 		vcpu->stat.instruction_sigp_emergency++;
3183d95c7d2SDavid Hildenbrand 		rc = __sigp_emergency(vcpu, dst_vcpu);
3193526a66bSDavid Hildenbrand 		break;
3203526a66bSDavid Hildenbrand 	case SIGP_STOP:
3213526a66bSDavid Hildenbrand 		vcpu->stat.instruction_sigp_stop++;
322a6cc3108SDavid Hildenbrand 		rc = __sigp_stop(vcpu, dst_vcpu);
3233526a66bSDavid Hildenbrand 		break;
3243526a66bSDavid Hildenbrand 	case SIGP_STOP_AND_STORE_STATUS:
32542cb0c9fSDavid Hildenbrand 		vcpu->stat.instruction_sigp_stop_store_status++;
326a6cc3108SDavid Hildenbrand 		rc = __sigp_stop_and_store_status(vcpu, dst_vcpu, status_reg);
3273526a66bSDavid Hildenbrand 		break;
3283526a66bSDavid Hildenbrand 	case SIGP_STORE_STATUS_AT_ADDRESS:
32942cb0c9fSDavid Hildenbrand 		vcpu->stat.instruction_sigp_store_status++;
3303d95c7d2SDavid Hildenbrand 		rc = __sigp_store_status_at_addr(vcpu, dst_vcpu, parameter,
3313526a66bSDavid Hildenbrand 						 status_reg);
3323526a66bSDavid Hildenbrand 		break;
3333526a66bSDavid Hildenbrand 	case SIGP_SET_PREFIX:
3343526a66bSDavid Hildenbrand 		vcpu->stat.instruction_sigp_prefix++;
3353d95c7d2SDavid Hildenbrand 		rc = __sigp_set_prefix(vcpu, dst_vcpu, parameter, status_reg);
3363526a66bSDavid Hildenbrand 		break;
3373526a66bSDavid Hildenbrand 	case SIGP_COND_EMERGENCY_SIGNAL:
33842cb0c9fSDavid Hildenbrand 		vcpu->stat.instruction_sigp_cond_emergency++;
3393d95c7d2SDavid Hildenbrand 		rc = __sigp_conditional_emergency(vcpu, dst_vcpu, parameter,
3403526a66bSDavid Hildenbrand 						  status_reg);
3413526a66bSDavid Hildenbrand 		break;
3423526a66bSDavid Hildenbrand 	case SIGP_SENSE_RUNNING:
3433526a66bSDavid Hildenbrand 		vcpu->stat.instruction_sigp_sense_running++;
3443d95c7d2SDavid Hildenbrand 		rc = __sigp_sense_running(vcpu, dst_vcpu, status_reg);
3453526a66bSDavid Hildenbrand 		break;
3463526a66bSDavid Hildenbrand 	case SIGP_START:
34742cb0c9fSDavid Hildenbrand 		vcpu->stat.instruction_sigp_start++;
348b8983830SDavid Hildenbrand 		rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
3493526a66bSDavid Hildenbrand 		break;
3503526a66bSDavid Hildenbrand 	case SIGP_RESTART:
3513526a66bSDavid Hildenbrand 		vcpu->stat.instruction_sigp_restart++;
352b8983830SDavid Hildenbrand 		rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
353b8983830SDavid Hildenbrand 		break;
354b8983830SDavid Hildenbrand 	case SIGP_INITIAL_CPU_RESET:
35542cb0c9fSDavid Hildenbrand 		vcpu->stat.instruction_sigp_init_cpu_reset++;
356b8983830SDavid Hildenbrand 		rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
357b8983830SDavid Hildenbrand 		break;
358b8983830SDavid Hildenbrand 	case SIGP_CPU_RESET:
35942cb0c9fSDavid Hildenbrand 		vcpu->stat.instruction_sigp_cpu_reset++;
360b8983830SDavid Hildenbrand 		rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
3613526a66bSDavid Hildenbrand 		break;
3623526a66bSDavid Hildenbrand 	default:
36342cb0c9fSDavid Hildenbrand 		vcpu->stat.instruction_sigp_unknown++;
364b8983830SDavid Hildenbrand 		rc = __prepare_sigp_unknown(vcpu, dst_vcpu);
3653526a66bSDavid Hildenbrand 	}
3663526a66bSDavid Hildenbrand 
367b8983830SDavid Hildenbrand 	if (rc == -EOPNOTSUPP)
368b8983830SDavid Hildenbrand 		VCPU_EVENT(vcpu, 4,
369b8983830SDavid Hildenbrand 			   "sigp order %u -> cpu %x: handled in user space",
370b8983830SDavid Hildenbrand 			   order_code, dst_vcpu->vcpu_id);
371b8983830SDavid Hildenbrand 
3723526a66bSDavid Hildenbrand 	return rc;
3733526a66bSDavid Hildenbrand }
3743526a66bSDavid Hildenbrand 
handle_sigp_order_in_user_space(struct kvm_vcpu * vcpu,u8 order_code,u16 cpu_addr)3757cbde76bSChristian Borntraeger static int handle_sigp_order_in_user_space(struct kvm_vcpu *vcpu, u8 order_code,
3767cbde76bSChristian Borntraeger 					   u16 cpu_addr)
3772444b352SDavid Hildenbrand {
3782444b352SDavid Hildenbrand 	if (!vcpu->kvm->arch.user_sigp)
3792444b352SDavid Hildenbrand 		return 0;
3802444b352SDavid Hildenbrand 
3812444b352SDavid Hildenbrand 	switch (order_code) {
3822444b352SDavid Hildenbrand 	case SIGP_SENSE:
3832444b352SDavid Hildenbrand 	case SIGP_EXTERNAL_CALL:
3842444b352SDavid Hildenbrand 	case SIGP_EMERGENCY_SIGNAL:
3852444b352SDavid Hildenbrand 	case SIGP_COND_EMERGENCY_SIGNAL:
3862444b352SDavid Hildenbrand 	case SIGP_SENSE_RUNNING:
3872444b352SDavid Hildenbrand 		return 0;
3882444b352SDavid Hildenbrand 	/* update counters as we're directly dropping to user space */
3892444b352SDavid Hildenbrand 	case SIGP_STOP:
3902444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_stop++;
3912444b352SDavid Hildenbrand 		break;
3922444b352SDavid Hildenbrand 	case SIGP_STOP_AND_STORE_STATUS:
3932444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_stop_store_status++;
3942444b352SDavid Hildenbrand 		break;
3952444b352SDavid Hildenbrand 	case SIGP_STORE_STATUS_AT_ADDRESS:
3962444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_store_status++;
3972444b352SDavid Hildenbrand 		break;
398cd7b4b61SEric Farman 	case SIGP_STORE_ADDITIONAL_STATUS:
399cd7b4b61SEric Farman 		vcpu->stat.instruction_sigp_store_adtl_status++;
400cd7b4b61SEric Farman 		break;
4012444b352SDavid Hildenbrand 	case SIGP_SET_PREFIX:
4022444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_prefix++;
4032444b352SDavid Hildenbrand 		break;
4042444b352SDavid Hildenbrand 	case SIGP_START:
4052444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_start++;
4062444b352SDavid Hildenbrand 		break;
4072444b352SDavid Hildenbrand 	case SIGP_RESTART:
4082444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_restart++;
4092444b352SDavid Hildenbrand 		break;
4102444b352SDavid Hildenbrand 	case SIGP_INITIAL_CPU_RESET:
4112444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_init_cpu_reset++;
4122444b352SDavid Hildenbrand 		break;
4132444b352SDavid Hildenbrand 	case SIGP_CPU_RESET:
4142444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_cpu_reset++;
4152444b352SDavid Hildenbrand 		break;
4162444b352SDavid Hildenbrand 	default:
4172444b352SDavid Hildenbrand 		vcpu->stat.instruction_sigp_unknown++;
4182444b352SDavid Hildenbrand 	}
4197cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 3, "SIGP: order %u for CPU %d handled in userspace",
4207cbde76bSChristian Borntraeger 		   order_code, cpu_addr);
4212444b352SDavid Hildenbrand 
4222444b352SDavid Hildenbrand 	return 1;
4232444b352SDavid Hildenbrand }
4242444b352SDavid Hildenbrand 
kvm_s390_handle_sigp(struct kvm_vcpu * vcpu)4255288fbf0SChristian Borntraeger int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
4265288fbf0SChristian Borntraeger {
4275288fbf0SChristian Borntraeger 	int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
4285288fbf0SChristian Borntraeger 	int r3 = vcpu->arch.sie_block->ipa & 0x000f;
4295288fbf0SChristian Borntraeger 	u32 parameter;
4305a32c1afSChristian Borntraeger 	u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
4315288fbf0SChristian Borntraeger 	u8 order_code;
4325288fbf0SChristian Borntraeger 	int rc;
4335288fbf0SChristian Borntraeger 
4343eb77d51SChristian Borntraeger 	/* sigp in userspace can exit */
4353eb77d51SChristian Borntraeger 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
436208dd756SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
4373eb77d51SChristian Borntraeger 
4388ae04b8fSAlexander Yarygin 	order_code = kvm_s390_get_base_disp_rs(vcpu, NULL);
4397cbde76bSChristian Borntraeger 	if (handle_sigp_order_in_user_space(vcpu, order_code, cpu_addr))
4402444b352SDavid Hildenbrand 		return -EOPNOTSUPP;
4415288fbf0SChristian Borntraeger 
4425288fbf0SChristian Borntraeger 	if (r1 % 2)
4435a32c1afSChristian Borntraeger 		parameter = vcpu->run->s.regs.gprs[r1];
4445288fbf0SChristian Borntraeger 	else
4455a32c1afSChristian Borntraeger 		parameter = vcpu->run->s.regs.gprs[r1 + 1];
4465288fbf0SChristian Borntraeger 
4475786fffaSCornelia Huck 	trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter);
4485288fbf0SChristian Borntraeger 	switch (order_code) {
449a9ae32c3SHeiko Carstens 	case SIGP_SET_ARCHITECTURE:
4505288fbf0SChristian Borntraeger 		vcpu->stat.instruction_sigp_arch++;
451b697e435SJason J. Herne 		rc = __sigp_set_arch(vcpu, parameter,
452b697e435SJason J. Herne 				     &vcpu->run->s.regs.gprs[r1]);
4535288fbf0SChristian Borntraeger 		break;
4545288fbf0SChristian Borntraeger 	default:
4553526a66bSDavid Hildenbrand 		rc = handle_sigp_dst(vcpu, order_code, cpu_addr,
4563526a66bSDavid Hildenbrand 				     parameter,
4573526a66bSDavid Hildenbrand 				     &vcpu->run->s.regs.gprs[r1]);
4585288fbf0SChristian Borntraeger 	}
4595288fbf0SChristian Borntraeger 
4605288fbf0SChristian Borntraeger 	if (rc < 0)
4615288fbf0SChristian Borntraeger 		return rc;
4625288fbf0SChristian Borntraeger 
463949c007aSThomas Huth 	kvm_s390_set_psw_cc(vcpu, rc);
4645288fbf0SChristian Borntraeger 	return 0;
4655288fbf0SChristian Borntraeger }
4664953919fSDavid Hildenbrand 
4674953919fSDavid Hildenbrand /*
4684953919fSDavid Hildenbrand  * Handle SIGP partial execution interception.
4694953919fSDavid Hildenbrand  *
4704953919fSDavid Hildenbrand  * This interception will occur at the source cpu when a source cpu sends an
4714953919fSDavid Hildenbrand  * external call to a target cpu and the target cpu has the WAIT bit set in
472*cada938aSHeiko Carstens  * its cpuflags. Interception will occur after the interrupt indicator bits at
4734953919fSDavid Hildenbrand  * the target cpu have been set. All error cases will lead to instruction
4744953919fSDavid Hildenbrand  * interception, therefore nothing is to be checked or prepared.
4754953919fSDavid Hildenbrand  */
kvm_s390_handle_sigp_pei(struct kvm_vcpu * vcpu)4764953919fSDavid Hildenbrand int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu)
4774953919fSDavid Hildenbrand {
4784953919fSDavid Hildenbrand 	int r3 = vcpu->arch.sie_block->ipa & 0x000f;
4794953919fSDavid Hildenbrand 	u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
4804953919fSDavid Hildenbrand 	struct kvm_vcpu *dest_vcpu;
4818ae04b8fSAlexander Yarygin 	u8 order_code = kvm_s390_get_base_disp_rs(vcpu, NULL);
4824953919fSDavid Hildenbrand 
483c3f0e5fdSNico Boehr 	if (order_code == SIGP_EXTERNAL_CALL) {
4844953919fSDavid Hildenbrand 		trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr);
4854953919fSDavid Hildenbrand 
486152e9f65SDavid Hildenbrand 		dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
4874953919fSDavid Hildenbrand 		BUG_ON(dest_vcpu == NULL);
4884953919fSDavid Hildenbrand 
4890e9c85a5SDavid Hildenbrand 		kvm_s390_vcpu_wakeup(dest_vcpu);
4904953919fSDavid Hildenbrand 		kvm_s390_set_psw_cc(vcpu, SIGP_CC_ORDER_CODE_ACCEPTED);
4914953919fSDavid Hildenbrand 		return 0;
4924953919fSDavid Hildenbrand 	}
4934953919fSDavid Hildenbrand 
4944953919fSDavid Hildenbrand 	return -EOPNOTSUPP;
4954953919fSDavid Hildenbrand }
496