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;
}