18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * handling interprocessor communication
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2008, 2013
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *    Author(s): Carsten Otte <cotte@de.ibm.com>
88c2ecf20Sopenharmony_ci *               Christian Borntraeger <borntraeger@de.ibm.com>
98c2ecf20Sopenharmony_ci *               Christian Ehrhardt <ehrhardt@de.ibm.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kvm.h>
138c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <asm/sigp.h>
168c2ecf20Sopenharmony_ci#include "gaccess.h"
178c2ecf20Sopenharmony_ci#include "kvm-s390.h"
188c2ecf20Sopenharmony_ci#include "trace.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
218c2ecf20Sopenharmony_ci			u64 *reg)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	const bool stopped = kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_STOPPED);
248c2ecf20Sopenharmony_ci	int rc;
258c2ecf20Sopenharmony_ci	int ext_call_pending;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	ext_call_pending = kvm_s390_ext_call_pending(dst_vcpu);
288c2ecf20Sopenharmony_ci	if (!stopped && !ext_call_pending)
298c2ecf20Sopenharmony_ci		rc = SIGP_CC_ORDER_CODE_ACCEPTED;
308c2ecf20Sopenharmony_ci	else {
318c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
328c2ecf20Sopenharmony_ci		if (ext_call_pending)
338c2ecf20Sopenharmony_ci			*reg |= SIGP_STATUS_EXT_CALL_PENDING;
348c2ecf20Sopenharmony_ci		if (stopped)
358c2ecf20Sopenharmony_ci			*reg |= SIGP_STATUS_STOPPED;
368c2ecf20Sopenharmony_ci		rc = SIGP_CC_STATUS_STORED;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", dst_vcpu->vcpu_id,
408c2ecf20Sopenharmony_ci		   rc);
418c2ecf20Sopenharmony_ci	return rc;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
458c2ecf20Sopenharmony_ci				    struct kvm_vcpu *dst_vcpu)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct kvm_s390_irq irq = {
488c2ecf20Sopenharmony_ci		.type = KVM_S390_INT_EMERGENCY,
498c2ecf20Sopenharmony_ci		.u.emerg.code = vcpu->vcpu_id,
508c2ecf20Sopenharmony_ci	};
518c2ecf20Sopenharmony_ci	int rc = 0;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
548c2ecf20Sopenharmony_ci	if (!rc)
558c2ecf20Sopenharmony_ci		VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
568c2ecf20Sopenharmony_ci			   dst_vcpu->vcpu_id);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int __sigp_emergency(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return __inject_sigp_emergency(vcpu, dst_vcpu);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
678c2ecf20Sopenharmony_ci					struct kvm_vcpu *dst_vcpu,
688c2ecf20Sopenharmony_ci					u16 asn, u64 *reg)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	const u64 psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
718c2ecf20Sopenharmony_ci	u16 p_asn, s_asn;
728c2ecf20Sopenharmony_ci	psw_t *psw;
738c2ecf20Sopenharmony_ci	bool idle;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	idle = is_vcpu_idle(vcpu);
768c2ecf20Sopenharmony_ci	psw = &dst_vcpu->arch.sie_block->gpsw;
778c2ecf20Sopenharmony_ci	p_asn = dst_vcpu->arch.sie_block->gcr[4] & 0xffff;  /* Primary ASN */
788c2ecf20Sopenharmony_ci	s_asn = dst_vcpu->arch.sie_block->gcr[3] & 0xffff;  /* Secondary ASN */
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* Inject the emergency signal? */
818c2ecf20Sopenharmony_ci	if (!is_vcpu_stopped(vcpu)
828c2ecf20Sopenharmony_ci	    || (psw->mask & psw_int_mask) != psw_int_mask
838c2ecf20Sopenharmony_ci	    || (idle && psw->addr != 0)
848c2ecf20Sopenharmony_ci	    || (!idle && (asn == p_asn || asn == s_asn))) {
858c2ecf20Sopenharmony_ci		return __inject_sigp_emergency(vcpu, dst_vcpu);
868c2ecf20Sopenharmony_ci	} else {
878c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
888c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_INCORRECT_STATE;
898c2ecf20Sopenharmony_ci		return SIGP_CC_STATUS_STORED;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int __sigp_external_call(struct kvm_vcpu *vcpu,
948c2ecf20Sopenharmony_ci				struct kvm_vcpu *dst_vcpu, u64 *reg)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct kvm_s390_irq irq = {
978c2ecf20Sopenharmony_ci		.type = KVM_S390_INT_EXTERNAL_CALL,
988c2ecf20Sopenharmony_ci		.u.extcall.code = vcpu->vcpu_id,
998c2ecf20Sopenharmony_ci	};
1008c2ecf20Sopenharmony_ci	int rc;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
1038c2ecf20Sopenharmony_ci	if (rc == -EBUSY) {
1048c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
1058c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_EXT_CALL_PENDING;
1068c2ecf20Sopenharmony_ci		return SIGP_CC_STATUS_STORED;
1078c2ecf20Sopenharmony_ci	} else if (rc == 0) {
1088c2ecf20Sopenharmony_ci		VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
1098c2ecf20Sopenharmony_ci			   dst_vcpu->vcpu_id);
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int __sigp_stop(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct kvm_s390_irq irq = {
1188c2ecf20Sopenharmony_ci		.type = KVM_S390_SIGP_STOP,
1198c2ecf20Sopenharmony_ci	};
1208c2ecf20Sopenharmony_ci	int rc;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
1238c2ecf20Sopenharmony_ci	if (rc == -EBUSY)
1248c2ecf20Sopenharmony_ci		rc = SIGP_CC_BUSY;
1258c2ecf20Sopenharmony_ci	else if (rc == 0)
1268c2ecf20Sopenharmony_ci		VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x",
1278c2ecf20Sopenharmony_ci			   dst_vcpu->vcpu_id);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return rc;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int __sigp_stop_and_store_status(struct kvm_vcpu *vcpu,
1338c2ecf20Sopenharmony_ci					struct kvm_vcpu *dst_vcpu, u64 *reg)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct kvm_s390_irq irq = {
1368c2ecf20Sopenharmony_ci		.type = KVM_S390_SIGP_STOP,
1378c2ecf20Sopenharmony_ci		.u.stop.flags = KVM_S390_STOP_FLAG_STORE_STATUS,
1388c2ecf20Sopenharmony_ci	};
1398c2ecf20Sopenharmony_ci	int rc;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
1428c2ecf20Sopenharmony_ci	if (rc == -EBUSY)
1438c2ecf20Sopenharmony_ci		rc = SIGP_CC_BUSY;
1448c2ecf20Sopenharmony_ci	else if (rc == 0)
1458c2ecf20Sopenharmony_ci		VCPU_EVENT(vcpu, 4, "sent sigp stop and store status to cpu %x",
1468c2ecf20Sopenharmony_ci			   dst_vcpu->vcpu_id);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return rc;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter,
1528c2ecf20Sopenharmony_ci			   u64 *status_reg)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	unsigned int i;
1558c2ecf20Sopenharmony_ci	struct kvm_vcpu *v;
1568c2ecf20Sopenharmony_ci	bool all_stopped = true;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	kvm_for_each_vcpu(i, v, vcpu->kvm) {
1598c2ecf20Sopenharmony_ci		if (v == vcpu)
1608c2ecf20Sopenharmony_ci			continue;
1618c2ecf20Sopenharmony_ci		if (!is_vcpu_stopped(v))
1628c2ecf20Sopenharmony_ci			all_stopped = false;
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	*status_reg &= 0xffffffff00000000UL;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* Reject set arch order, with czam we're always in z/Arch mode. */
1688c2ecf20Sopenharmony_ci	*status_reg |= (all_stopped ? SIGP_STATUS_INVALID_PARAMETER :
1698c2ecf20Sopenharmony_ci					SIGP_STATUS_INCORRECT_STATE);
1708c2ecf20Sopenharmony_ci	return SIGP_CC_STATUS_STORED;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
1748c2ecf20Sopenharmony_ci			     u32 address, u64 *reg)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct kvm_s390_irq irq = {
1778c2ecf20Sopenharmony_ci		.type = KVM_S390_SIGP_SET_PREFIX,
1788c2ecf20Sopenharmony_ci		.u.prefix.address = address & 0x7fffe000u,
1798c2ecf20Sopenharmony_ci	};
1808c2ecf20Sopenharmony_ci	int rc;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/*
1838c2ecf20Sopenharmony_ci	 * Make sure the new value is valid memory. We only need to check the
1848c2ecf20Sopenharmony_ci	 * first page, since address is 8k aligned and memory pieces are always
1858c2ecf20Sopenharmony_ci	 * at least 1MB aligned and have at least a size of 1MB.
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci	if (kvm_is_error_gpa(vcpu->kvm, irq.u.prefix.address)) {
1888c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
1898c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_INVALID_PARAMETER;
1908c2ecf20Sopenharmony_ci		return SIGP_CC_STATUS_STORED;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
1948c2ecf20Sopenharmony_ci	if (rc == -EBUSY) {
1958c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
1968c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_INCORRECT_STATE;
1978c2ecf20Sopenharmony_ci		return SIGP_CC_STATUS_STORED;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	return rc;
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu,
2048c2ecf20Sopenharmony_ci				       struct kvm_vcpu *dst_vcpu,
2058c2ecf20Sopenharmony_ci				       u32 addr, u64 *reg)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	int rc;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (!kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_STOPPED)) {
2108c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
2118c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_INCORRECT_STATE;
2128c2ecf20Sopenharmony_ci		return SIGP_CC_STATUS_STORED;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	addr &= 0x7ffffe00;
2168c2ecf20Sopenharmony_ci	rc = kvm_s390_store_status_unloaded(dst_vcpu, addr);
2178c2ecf20Sopenharmony_ci	if (rc == -EFAULT) {
2188c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
2198c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_INVALID_PARAMETER;
2208c2ecf20Sopenharmony_ci		rc = SIGP_CC_STATUS_STORED;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	return rc;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int __sigp_sense_running(struct kvm_vcpu *vcpu,
2268c2ecf20Sopenharmony_ci				struct kvm_vcpu *dst_vcpu, u64 *reg)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	int rc;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (!test_kvm_facility(vcpu->kvm, 9)) {
2318c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
2328c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_INVALID_ORDER;
2338c2ecf20Sopenharmony_ci		return SIGP_CC_STATUS_STORED;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_RUNNING)) {
2378c2ecf20Sopenharmony_ci		/* running */
2388c2ecf20Sopenharmony_ci		rc = SIGP_CC_ORDER_CODE_ACCEPTED;
2398c2ecf20Sopenharmony_ci	} else {
2408c2ecf20Sopenharmony_ci		/* not running */
2418c2ecf20Sopenharmony_ci		*reg &= 0xffffffff00000000UL;
2428c2ecf20Sopenharmony_ci		*reg |= SIGP_STATUS_NOT_RUNNING;
2438c2ecf20Sopenharmony_ci		rc = SIGP_CC_STATUS_STORED;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x",
2478c2ecf20Sopenharmony_ci		   dst_vcpu->vcpu_id, rc);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return rc;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int __prepare_sigp_re_start(struct kvm_vcpu *vcpu,
2538c2ecf20Sopenharmony_ci				   struct kvm_vcpu *dst_vcpu, u8 order_code)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
2568c2ecf20Sopenharmony_ci	/* handle (RE)START in user space */
2578c2ecf20Sopenharmony_ci	int rc = -EOPNOTSUPP;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* make sure we don't race with STOP irq injection */
2608c2ecf20Sopenharmony_ci	spin_lock(&li->lock);
2618c2ecf20Sopenharmony_ci	if (kvm_s390_is_stop_irq_pending(dst_vcpu))
2628c2ecf20Sopenharmony_ci		rc = SIGP_CC_BUSY;
2638c2ecf20Sopenharmony_ci	spin_unlock(&li->lock);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return rc;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic int __prepare_sigp_cpu_reset(struct kvm_vcpu *vcpu,
2698c2ecf20Sopenharmony_ci				    struct kvm_vcpu *dst_vcpu, u8 order_code)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	/* handle (INITIAL) CPU RESET in user space */
2728c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int __prepare_sigp_unknown(struct kvm_vcpu *vcpu,
2768c2ecf20Sopenharmony_ci				  struct kvm_vcpu *dst_vcpu)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	/* handle unknown orders in user space */
2798c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,
2838c2ecf20Sopenharmony_ci			   u16 cpu_addr, u32 parameter, u64 *status_reg)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	int rc;
2868c2ecf20Sopenharmony_ci	struct kvm_vcpu *dst_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (!dst_vcpu)
2898c2ecf20Sopenharmony_ci		return SIGP_CC_NOT_OPERATIONAL;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/*
2928c2ecf20Sopenharmony_ci	 * SIGP RESTART, SIGP STOP, and SIGP STOP AND STORE STATUS orders
2938c2ecf20Sopenharmony_ci	 * are processed asynchronously. Until the affected VCPU finishes
2948c2ecf20Sopenharmony_ci	 * its work and calls back into KVM to clear the (RESTART or STOP)
2958c2ecf20Sopenharmony_ci	 * interrupt, we need to return any new non-reset orders "busy".
2968c2ecf20Sopenharmony_ci	 *
2978c2ecf20Sopenharmony_ci	 * This is important because a single VCPU could issue:
2988c2ecf20Sopenharmony_ci	 *  1) SIGP STOP $DESTINATION
2998c2ecf20Sopenharmony_ci	 *  2) SIGP SENSE $DESTINATION
3008c2ecf20Sopenharmony_ci	 *
3018c2ecf20Sopenharmony_ci	 * If the SIGP SENSE would not be rejected as "busy", it could
3028c2ecf20Sopenharmony_ci	 * return an incorrect answer as to whether the VCPU is STOPPED
3038c2ecf20Sopenharmony_ci	 * or OPERATING.
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	if (order_code != SIGP_INITIAL_CPU_RESET &&
3068c2ecf20Sopenharmony_ci	    order_code != SIGP_CPU_RESET) {
3078c2ecf20Sopenharmony_ci		/*
3088c2ecf20Sopenharmony_ci		 * Lockless check. Both SIGP STOP and SIGP (RE)START
3098c2ecf20Sopenharmony_ci		 * properly synchronize everything while processing
3108c2ecf20Sopenharmony_ci		 * their orders, while the guest cannot observe a
3118c2ecf20Sopenharmony_ci		 * difference when issuing other orders from two
3128c2ecf20Sopenharmony_ci		 * different VCPUs.
3138c2ecf20Sopenharmony_ci		 */
3148c2ecf20Sopenharmony_ci		if (kvm_s390_is_stop_irq_pending(dst_vcpu) ||
3158c2ecf20Sopenharmony_ci		    kvm_s390_is_restart_irq_pending(dst_vcpu))
3168c2ecf20Sopenharmony_ci			return SIGP_CC_BUSY;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	switch (order_code) {
3208c2ecf20Sopenharmony_ci	case SIGP_SENSE:
3218c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_sense++;
3228c2ecf20Sopenharmony_ci		rc = __sigp_sense(vcpu, dst_vcpu, status_reg);
3238c2ecf20Sopenharmony_ci		break;
3248c2ecf20Sopenharmony_ci	case SIGP_EXTERNAL_CALL:
3258c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_external_call++;
3268c2ecf20Sopenharmony_ci		rc = __sigp_external_call(vcpu, dst_vcpu, status_reg);
3278c2ecf20Sopenharmony_ci		break;
3288c2ecf20Sopenharmony_ci	case SIGP_EMERGENCY_SIGNAL:
3298c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_emergency++;
3308c2ecf20Sopenharmony_ci		rc = __sigp_emergency(vcpu, dst_vcpu);
3318c2ecf20Sopenharmony_ci		break;
3328c2ecf20Sopenharmony_ci	case SIGP_STOP:
3338c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_stop++;
3348c2ecf20Sopenharmony_ci		rc = __sigp_stop(vcpu, dst_vcpu);
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci	case SIGP_STOP_AND_STORE_STATUS:
3378c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_stop_store_status++;
3388c2ecf20Sopenharmony_ci		rc = __sigp_stop_and_store_status(vcpu, dst_vcpu, status_reg);
3398c2ecf20Sopenharmony_ci		break;
3408c2ecf20Sopenharmony_ci	case SIGP_STORE_STATUS_AT_ADDRESS:
3418c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_store_status++;
3428c2ecf20Sopenharmony_ci		rc = __sigp_store_status_at_addr(vcpu, dst_vcpu, parameter,
3438c2ecf20Sopenharmony_ci						 status_reg);
3448c2ecf20Sopenharmony_ci		break;
3458c2ecf20Sopenharmony_ci	case SIGP_SET_PREFIX:
3468c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_prefix++;
3478c2ecf20Sopenharmony_ci		rc = __sigp_set_prefix(vcpu, dst_vcpu, parameter, status_reg);
3488c2ecf20Sopenharmony_ci		break;
3498c2ecf20Sopenharmony_ci	case SIGP_COND_EMERGENCY_SIGNAL:
3508c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_cond_emergency++;
3518c2ecf20Sopenharmony_ci		rc = __sigp_conditional_emergency(vcpu, dst_vcpu, parameter,
3528c2ecf20Sopenharmony_ci						  status_reg);
3538c2ecf20Sopenharmony_ci		break;
3548c2ecf20Sopenharmony_ci	case SIGP_SENSE_RUNNING:
3558c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_sense_running++;
3568c2ecf20Sopenharmony_ci		rc = __sigp_sense_running(vcpu, dst_vcpu, status_reg);
3578c2ecf20Sopenharmony_ci		break;
3588c2ecf20Sopenharmony_ci	case SIGP_START:
3598c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_start++;
3608c2ecf20Sopenharmony_ci		rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
3618c2ecf20Sopenharmony_ci		break;
3628c2ecf20Sopenharmony_ci	case SIGP_RESTART:
3638c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_restart++;
3648c2ecf20Sopenharmony_ci		rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	case SIGP_INITIAL_CPU_RESET:
3678c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_init_cpu_reset++;
3688c2ecf20Sopenharmony_ci		rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
3698c2ecf20Sopenharmony_ci		break;
3708c2ecf20Sopenharmony_ci	case SIGP_CPU_RESET:
3718c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_cpu_reset++;
3728c2ecf20Sopenharmony_ci		rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci	default:
3758c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_unknown++;
3768c2ecf20Sopenharmony_ci		rc = __prepare_sigp_unknown(vcpu, dst_vcpu);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (rc == -EOPNOTSUPP)
3808c2ecf20Sopenharmony_ci		VCPU_EVENT(vcpu, 4,
3818c2ecf20Sopenharmony_ci			   "sigp order %u -> cpu %x: handled in user space",
3828c2ecf20Sopenharmony_ci			   order_code, dst_vcpu->vcpu_id);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return rc;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int handle_sigp_order_in_user_space(struct kvm_vcpu *vcpu, u8 order_code,
3888c2ecf20Sopenharmony_ci					   u16 cpu_addr)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	if (!vcpu->kvm->arch.user_sigp)
3918c2ecf20Sopenharmony_ci		return 0;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	switch (order_code) {
3948c2ecf20Sopenharmony_ci	case SIGP_SENSE:
3958c2ecf20Sopenharmony_ci	case SIGP_EXTERNAL_CALL:
3968c2ecf20Sopenharmony_ci	case SIGP_EMERGENCY_SIGNAL:
3978c2ecf20Sopenharmony_ci	case SIGP_COND_EMERGENCY_SIGNAL:
3988c2ecf20Sopenharmony_ci	case SIGP_SENSE_RUNNING:
3998c2ecf20Sopenharmony_ci		return 0;
4008c2ecf20Sopenharmony_ci	/* update counters as we're directly dropping to user space */
4018c2ecf20Sopenharmony_ci	case SIGP_STOP:
4028c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_stop++;
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	case SIGP_STOP_AND_STORE_STATUS:
4058c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_stop_store_status++;
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	case SIGP_STORE_STATUS_AT_ADDRESS:
4088c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_store_status++;
4098c2ecf20Sopenharmony_ci		break;
4108c2ecf20Sopenharmony_ci	case SIGP_STORE_ADDITIONAL_STATUS:
4118c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_store_adtl_status++;
4128c2ecf20Sopenharmony_ci		break;
4138c2ecf20Sopenharmony_ci	case SIGP_SET_PREFIX:
4148c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_prefix++;
4158c2ecf20Sopenharmony_ci		break;
4168c2ecf20Sopenharmony_ci	case SIGP_START:
4178c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_start++;
4188c2ecf20Sopenharmony_ci		break;
4198c2ecf20Sopenharmony_ci	case SIGP_RESTART:
4208c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_restart++;
4218c2ecf20Sopenharmony_ci		break;
4228c2ecf20Sopenharmony_ci	case SIGP_INITIAL_CPU_RESET:
4238c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_init_cpu_reset++;
4248c2ecf20Sopenharmony_ci		break;
4258c2ecf20Sopenharmony_ci	case SIGP_CPU_RESET:
4268c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_cpu_reset++;
4278c2ecf20Sopenharmony_ci		break;
4288c2ecf20Sopenharmony_ci	default:
4298c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_unknown++;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci	VCPU_EVENT(vcpu, 3, "SIGP: order %u for CPU %d handled in userspace",
4328c2ecf20Sopenharmony_ci		   order_code, cpu_addr);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return 1;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciint kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
4408c2ecf20Sopenharmony_ci	int r3 = vcpu->arch.sie_block->ipa & 0x000f;
4418c2ecf20Sopenharmony_ci	u32 parameter;
4428c2ecf20Sopenharmony_ci	u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
4438c2ecf20Sopenharmony_ci	u8 order_code;
4448c2ecf20Sopenharmony_ci	int rc;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/* sigp in userspace can exit */
4478c2ecf20Sopenharmony_ci	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
4488c2ecf20Sopenharmony_ci		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	order_code = kvm_s390_get_base_disp_rs(vcpu, NULL);
4518c2ecf20Sopenharmony_ci	if (handle_sigp_order_in_user_space(vcpu, order_code, cpu_addr))
4528c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (r1 % 2)
4558c2ecf20Sopenharmony_ci		parameter = vcpu->run->s.regs.gprs[r1];
4568c2ecf20Sopenharmony_ci	else
4578c2ecf20Sopenharmony_ci		parameter = vcpu->run->s.regs.gprs[r1 + 1];
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter);
4608c2ecf20Sopenharmony_ci	switch (order_code) {
4618c2ecf20Sopenharmony_ci	case SIGP_SET_ARCHITECTURE:
4628c2ecf20Sopenharmony_ci		vcpu->stat.instruction_sigp_arch++;
4638c2ecf20Sopenharmony_ci		rc = __sigp_set_arch(vcpu, parameter,
4648c2ecf20Sopenharmony_ci				     &vcpu->run->s.regs.gprs[r1]);
4658c2ecf20Sopenharmony_ci		break;
4668c2ecf20Sopenharmony_ci	default:
4678c2ecf20Sopenharmony_ci		rc = handle_sigp_dst(vcpu, order_code, cpu_addr,
4688c2ecf20Sopenharmony_ci				     parameter,
4698c2ecf20Sopenharmony_ci				     &vcpu->run->s.regs.gprs[r1]);
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (rc < 0)
4738c2ecf20Sopenharmony_ci		return rc;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	kvm_s390_set_psw_cc(vcpu, rc);
4768c2ecf20Sopenharmony_ci	return 0;
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci/*
4808c2ecf20Sopenharmony_ci * Handle SIGP partial execution interception.
4818c2ecf20Sopenharmony_ci *
4828c2ecf20Sopenharmony_ci * This interception will occur at the source cpu when a source cpu sends an
4838c2ecf20Sopenharmony_ci * external call to a target cpu and the target cpu has the WAIT bit set in
4848c2ecf20Sopenharmony_ci * its cpuflags. Interception will occurr after the interrupt indicator bits at
4858c2ecf20Sopenharmony_ci * the target cpu have been set. All error cases will lead to instruction
4868c2ecf20Sopenharmony_ci * interception, therefore nothing is to be checked or prepared.
4878c2ecf20Sopenharmony_ci */
4888c2ecf20Sopenharmony_ciint kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	int r3 = vcpu->arch.sie_block->ipa & 0x000f;
4918c2ecf20Sopenharmony_ci	u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
4928c2ecf20Sopenharmony_ci	struct kvm_vcpu *dest_vcpu;
4938c2ecf20Sopenharmony_ci	u8 order_code = kvm_s390_get_base_disp_rs(vcpu, NULL);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (order_code == SIGP_EXTERNAL_CALL) {
4968c2ecf20Sopenharmony_ci		trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
4998c2ecf20Sopenharmony_ci		BUG_ON(dest_vcpu == NULL);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		kvm_s390_vcpu_wakeup(dest_vcpu);
5028c2ecf20Sopenharmony_ci		kvm_s390_set_psw_cc(vcpu, SIGP_CC_ORDER_CODE_ACCEPTED);
5038c2ecf20Sopenharmony_ci		return 0;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
5078c2ecf20Sopenharmony_ci}
508