KVM: s390: vsie: simulate VCPU SIE entry/exit
authorDavid Hildenbrand <david@redhat.com>
Tue, 25 Sep 2018 23:16:16 +0000 (19:16 -0400)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Wed, 26 Sep 2018 07:13:20 +0000 (09:13 +0200)
VCPU requests and VCPU blocking right now don't take care of the vSIE
(as it was not necessary until now). But we want to have synchronous VCPU
requests that will also be handled before running the vSIE again.

So let's simulate a SIE entry of the VCPU when calling the sie during
vSIE handling and check for PROG_ flags. The existing infrastructure
(e.g. exit_sie()) will then detect that the SIE (in form of the vSIE) is
running and properly kick the vSIE CPU, resulting in it leaving the vSIE
loop and therefore the vSIE interception handler, allowing it to handle
VCPU requests.

E.g. if we want to modify the crycb of the VCPU and make sure that any
masks also get applied to the VSIE crycb shadow (which uses masks from the
VCPU crycb), we will need a way to hinder the vSIE from running and make
sure to process the updated crycb before reentering the vSIE again.

Signed-off-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Pierre Morel <pmorel@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Message-Id: <20180925231641.4954-2-akrowiak@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/vsie.c

index f69333fd2fa3818c5eeb8bff9240f67e29f37ef0..0b5aff0e3984218c51ff2398a2004f74c7533633 100644 (file)
@@ -2768,18 +2768,25 @@ static void kvm_s390_vcpu_request(struct kvm_vcpu *vcpu)
        exit_sie(vcpu);
 }
 
+bool kvm_s390_vcpu_sie_inhibited(struct kvm_vcpu *vcpu)
+{
+       return atomic_read(&vcpu->arch.sie_block->prog20) &
+              (PROG_BLOCK_SIE | PROG_REQUEST);
+}
+
 static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu)
 {
        atomic_andnot(PROG_REQUEST, &vcpu->arch.sie_block->prog20);
 }
 
 /*
- * Kick a guest cpu out of SIE and wait until SIE is not running.
+ * Kick a guest cpu out of (v)SIE and wait until (v)SIE is not running.
  * If the CPU is not running (e.g. waiting as idle) the function will
  * return immediately. */
 void exit_sie(struct kvm_vcpu *vcpu)
 {
        kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT);
+       kvm_s390_vsie_kick(vcpu);
        while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE)
                cpu_relax();
 }
index 981e3ba974616d5597e5ebd87a58c78e2d11ca27..1f6e36cdce0da88f8f0e54a772011e7080d2723c 100644 (file)
@@ -290,6 +290,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_block(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu);
+bool kvm_s390_vcpu_sie_inhibited(struct kvm_vcpu *vcpu);
 void exit_sie(struct kvm_vcpu *vcpu);
 void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu);
 int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu);
index a2b28cd1e3fedb2bdcc6dbb1cff530ba0e3371a7..12b970701c264071b2d2f8fd77c23c16135018b7 100644 (file)
@@ -830,7 +830,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
        struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
        int guest_bp_isolation;
-       int rc;
+       int rc = 0;
 
        handle_last_fault(vcpu, vsie_page);
 
@@ -858,7 +858,18 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        guest_enter_irqoff();
        local_irq_enable();
 
-       rc = sie64a(scb_s, vcpu->run->s.regs.gprs);
+       /*
+        * Simulate a SIE entry of the VCPU (see sie64a), so VCPU blocking
+        * and VCPU requests also hinder the vSIE from running and lead
+        * to an immediate exit. kvm_s390_vsie_kick() has to be used to
+        * also kick the vSIE.
+        */
+       vcpu->arch.sie_block->prog0c |= PROG_IN_SIE;
+       barrier();
+       if (!kvm_s390_vcpu_sie_inhibited(vcpu))
+               rc = sie64a(scb_s, vcpu->run->s.regs.gprs);
+       barrier();
+       vcpu->arch.sie_block->prog0c &= ~PROG_IN_SIE;
 
        local_irq_disable();
        guest_exit_irqoff();
@@ -1005,7 +1016,8 @@ 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) ||
-                   kvm_s390_vcpu_has_irq(vcpu, 0))
+                   kvm_s390_vcpu_has_irq(vcpu, 0) ||
+                   kvm_s390_vcpu_sie_inhibited(vcpu))
                        break;
        }
 
@@ -1122,7 +1134,8 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
        if (unlikely(scb_addr & 0x1ffUL))
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
-       if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0))
+       if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0) ||
+           kvm_s390_vcpu_sie_inhibited(vcpu))
                return 0;
 
        vsie_page = get_vsie_page(vcpu->kvm, scb_addr);