@@ -460,11 +460,36 @@ static int handle_pv_spx(struct kvm_vcpu *vcpu)
return 0;
}
+static int handle_pv_sclp(struct kvm_vcpu *vcpu)
+{
+ struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+
+ spin_lock(&fi->lock);
+ /*
+ * 2 cases:
+ * a: an sccb answering interrupt was already pending or in flight.
+ * As the sccb value is not used we can simply set some more bits
+ * and make sure that we deliver something
+ * b: an error sccb interrupt needs to be injected so we also inject
+ * something and let firmware do the right thing.
+ * This makes sure, that both errors and real sccb returns will only
+ * be delivered when we are unmasked.
+ */
+ fi->srv_signal.ext_params |= 0x43000;
+ set_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs);
+ clear_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs);
+ spin_unlock(&fi->lock);
+ return 0;
+}
+
static int handle_pv_not(struct kvm_vcpu *vcpu)
{
if (vcpu->arch.sie_block->ipa == 0xb210)
return handle_pv_spx(vcpu);
+ if (vcpu->arch.sie_block->ipa == 0xb220)
+ return handle_pv_sclp(vcpu);
+
return handle_instruction(vcpu);
}
@@ -2189,6 +2189,8 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
if (!r)
r = kvm_s390_pv_create_vm(kvm);
kvm_s390_vcpu_unblock_all(kvm);
+ /* we need to block service interrupts from now on */
+ set_bit(IRQ_PEND_EXT_SERVICE,&kvm->arch.float_int.masked_irqs);
mutex_unlock(&kvm->lock);
break;
}