]> www.infradead.org Git - nvme.git/commitdiff
KVM: s390: vsie: retry SIE instruction on host intercepts
authorEric Farman <farman@linux.ibm.com>
Fri, 1 Mar 2024 20:43:42 +0000 (21:43 +0100)
committerJanosch Frank <frankja@linux.ibm.com>
Thu, 4 Jul 2024 07:07:00 +0000 (09:07 +0200)
It's possible that SIE exits for work that the host needs to perform
rather than something that is intended for the guest.

A Linux guest will ignore this intercept code since there is nothing
for it to do, but a more robust solution would rewind the PSW back to
the SIE instruction. This will transparently resume the guest once
the host completes its work, without the guest needing to process
what is effectively a NOP and re-issue SIE itself.

Signed-off-by: Eric Farman <farman@linux.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Link: https://lore.kernel.org/r/20240301204342.3217540-1-farman@linux.ibm.com
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Message-ID: <20240301204342.3217540-1-farman@linux.ibm.com>

arch/s390/kvm/vsie.c

index c9ecae830634f5f73863736c1e2137a7b08728e2..54deafd0d6983bfc31bf9b46e2109426149425b3 100644 (file)
@@ -1304,10 +1304,24 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 
                if (rc == -EAGAIN)
                        rc = 0;
-               if (rc || scb_s->icptcode || signal_pending(current) ||
+
+               /*
+                * Exit the loop if the guest needs to process the intercept
+                */
+               if (rc || scb_s->icptcode)
+                       break;
+
+               /*
+                * Exit the loop if the host needs to process an intercept,
+                * but rewind the PSW to re-enter SIE once that's completed
+                * instead of passing a "no action" intercept to the guest.
+                */
+               if (signal_pending(current) ||
                    kvm_s390_vcpu_has_irq(vcpu, 0) ||
-                   kvm_s390_vcpu_sie_inhibited(vcpu))
+                   kvm_s390_vcpu_sie_inhibited(vcpu)) {
+                       kvm_s390_rewind_psw(vcpu, 4);
                        break;
+               }
                cond_resched();
        }
 
@@ -1426,8 +1440,10 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
        if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0) ||
-           kvm_s390_vcpu_sie_inhibited(vcpu))
+           kvm_s390_vcpu_sie_inhibited(vcpu)) {
+               kvm_s390_rewind_psw(vcpu, 4);
                return 0;
+       }
 
        vsie_page = get_vsie_page(vcpu->kvm, scb_addr);
        if (IS_ERR(vsie_page))