static int handle_sigp_dst()

in kvm/sigp.c [270:373]


static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,
			   u16 cpu_addr, u32 parameter, u64 *status_reg)
{
	int rc;
	struct kvm_vcpu *dst_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);

	if (!dst_vcpu)
		return SIGP_CC_NOT_OPERATIONAL;

	/*
	 * SIGP RESTART, SIGP STOP, and SIGP STOP AND STORE STATUS orders
	 * are processed asynchronously. Until the affected VCPU finishes
	 * its work and calls back into KVM to clear the (RESTART or STOP)
	 * interrupt, we need to return any new non-reset orders "busy".
	 *
	 * This is important because a single VCPU could issue:
	 *  1) SIGP STOP $DESTINATION
	 *  2) SIGP SENSE $DESTINATION
	 *
	 * If the SIGP SENSE would not be rejected as "busy", it could
	 * return an incorrect answer as to whether the VCPU is STOPPED
	 * or OPERATING.
	 */
	if (order_code != SIGP_INITIAL_CPU_RESET &&
	    order_code != SIGP_CPU_RESET) {
		/*
		 * Lockless check. Both SIGP STOP and SIGP (RE)START
		 * properly synchronize everything while processing
		 * their orders, while the guest cannot observe a
		 * difference when issuing other orders from two
		 * different VCPUs.
		 */
		if (kvm_s390_is_stop_irq_pending(dst_vcpu) ||
		    kvm_s390_is_restart_irq_pending(dst_vcpu))
			return SIGP_CC_BUSY;
	}

	switch (order_code) {
	case SIGP_SENSE:
		vcpu->stat.instruction_sigp_sense++;
		rc = __sigp_sense(vcpu, dst_vcpu, status_reg);
		break;
	case SIGP_EXTERNAL_CALL:
		vcpu->stat.instruction_sigp_external_call++;
		rc = __sigp_external_call(vcpu, dst_vcpu, status_reg);
		break;
	case SIGP_EMERGENCY_SIGNAL:
		vcpu->stat.instruction_sigp_emergency++;
		rc = __sigp_emergency(vcpu, dst_vcpu);
		break;
	case SIGP_STOP:
		vcpu->stat.instruction_sigp_stop++;
		rc = __sigp_stop(vcpu, dst_vcpu);
		break;
	case SIGP_STOP_AND_STORE_STATUS:
		vcpu->stat.instruction_sigp_stop_store_status++;
		rc = __sigp_stop_and_store_status(vcpu, dst_vcpu, status_reg);
		break;
	case SIGP_STORE_STATUS_AT_ADDRESS:
		vcpu->stat.instruction_sigp_store_status++;
		rc = __sigp_store_status_at_addr(vcpu, dst_vcpu, parameter,
						 status_reg);
		break;
	case SIGP_SET_PREFIX:
		vcpu->stat.instruction_sigp_prefix++;
		rc = __sigp_set_prefix(vcpu, dst_vcpu, parameter, status_reg);
		break;
	case SIGP_COND_EMERGENCY_SIGNAL:
		vcpu->stat.instruction_sigp_cond_emergency++;
		rc = __sigp_conditional_emergency(vcpu, dst_vcpu, parameter,
						  status_reg);
		break;
	case SIGP_SENSE_RUNNING:
		vcpu->stat.instruction_sigp_sense_running++;
		rc = __sigp_sense_running(vcpu, dst_vcpu, status_reg);
		break;
	case SIGP_START:
		vcpu->stat.instruction_sigp_start++;
		rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
		break;
	case SIGP_RESTART:
		vcpu->stat.instruction_sigp_restart++;
		rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
		break;
	case SIGP_INITIAL_CPU_RESET:
		vcpu->stat.instruction_sigp_init_cpu_reset++;
		rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
		break;
	case SIGP_CPU_RESET:
		vcpu->stat.instruction_sigp_cpu_reset++;
		rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
		break;
	default:
		vcpu->stat.instruction_sigp_unknown++;
		rc = __prepare_sigp_unknown(vcpu, dst_vcpu);
	}

	if (rc == -EOPNOTSUPP)
		VCPU_EVENT(vcpu, 4,
			   "sigp order %u -> cpu %x: handled in user space",
			   order_code, dst_vcpu->vcpu_id);

	return rc;
}