From: Nico Boehr nrb@linux.ibm.com
stable inclusion from stable-v5.10.137 commit e9c55562b3938917ccdc8ad85774ea49da018597 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I60PLB
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
commit c3f0e5fd2d33d80c5a5a8b5e5d2bab2841709cc8 upstream.
When the SIGP interpretation facility is present and a VCPU sends an ecall to another VCPU in enabled wait, the sending VCPU receives a 56 intercept (partial execution), so KVM can wake up the receiving CPU. Note that the SIGP interpretation facility will take care of the interrupt delivery and KVM's only job is to wake the receiving VCPU.
For PV, the sending VCPU will receive a 108 intercept (pv notify) and should continue like in the non-PV case, i.e. wake the receiving VCPU.
For PV and non-PV guests the interrupt delivery will occur through the SIGP interpretation facility on SIE entry when SIE finds the X bit in the status field set.
However, in handle_pv_notification(), there was no special handling for SIGP, which leads to interrupt injection being requested by KVM for the next SIE entry. This results in the interrupt being delivered twice: once by the SIGP interpretation facility and once by KVM through the IICTL.
Add the necessary special handling in handle_pv_notification(), similar to handle_partial_execution(), which simply wakes the receiving VCPU and leave interrupt delivery to the SIGP interpretation facility.
In contrast to external calls, emergency calls are not interpreted but also cause a 108 intercept, which is why we still need to call handle_instruction() for SIGP orders other than ecall.
Since kvm_s390_handle_sigp_pei() is now called for all SIGP orders which cause a 108 intercept - even if they are actually handled by handle_instruction() - move the tracepoint in kvm_s390_handle_sigp_pei() to avoid possibly confusing trace messages.
Signed-off-by: Nico Boehr nrb@linux.ibm.com Cc: stable@vger.kernel.org # 5.7 Fixes: da24a0cc58ed ("KVM: s390: protvirt: Instruction emulation") Reviewed-by: Claudio Imbrenda imbrenda@linux.ibm.com Reviewed-by: Janosch Frank frankja@linux.ibm.com Reviewed-by: Christian Borntraeger borntraeger@linux.ibm.com Link: https://lore.kernel.org/r/20220718130434.73302-1-nrb@linux.ibm.com Message-Id: 20220718130434.73302-1-nrb@linux.ibm.com Signed-off-by: Claudio Imbrenda imbrenda@linux.ibm.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Reviewed-by: Wei Li liwei391@huawei.com --- arch/s390/kvm/intercept.c | 15 +++++++++++++++ arch/s390/kvm/sigp.c | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index e7a7c499a73f..77909d362b78 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -521,12 +521,27 @@ static int handle_pv_uvc(struct kvm_vcpu *vcpu)
static int handle_pv_notification(struct kvm_vcpu *vcpu) { + int ret; + if (vcpu->arch.sie_block->ipa == 0xb210) return handle_pv_spx(vcpu); if (vcpu->arch.sie_block->ipa == 0xb220) return handle_pv_sclp(vcpu); if (vcpu->arch.sie_block->ipa == 0xb9a4) return handle_pv_uvc(vcpu); + if (vcpu->arch.sie_block->ipa >> 8 == 0xae) { + /* + * Besides external call, other SIGP orders also cause a + * 108 (pv notify) intercept. In contrast to external call, + * these orders need to be emulated and hence the appropriate + * place to handle them is in handle_instruction(). + * So first try kvm_s390_handle_sigp_pei() and if that isn't + * successful, go on with handle_instruction(). + */ + ret = kvm_s390_handle_sigp_pei(vcpu); + if (!ret) + return ret; + }
return handle_instruction(vcpu); } diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 3dc921e853b6..52800279686c 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -492,9 +492,9 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu) struct kvm_vcpu *dest_vcpu; u8 order_code = kvm_s390_get_base_disp_rs(vcpu, NULL);
- trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr); - if (order_code == SIGP_EXTERNAL_CALL) { + trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr); + dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr); BUG_ON(dest_vcpu == NULL);