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