These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / s390 / kvm / guestdbg.c
index e97b345..47518a3 100644 (file)
@@ -473,10 +473,45 @@ static void filter_guest_per_event(struct kvm_vcpu *vcpu)
                vcpu->arch.sie_block->iprcc &= ~PGM_PER;
 }
 
+#define pssec(vcpu) (vcpu->arch.sie_block->gcr[1] & _ASCE_SPACE_SWITCH)
+#define hssec(vcpu) (vcpu->arch.sie_block->gcr[13] & _ASCE_SPACE_SWITCH)
+#define old_ssec(vcpu) ((vcpu->arch.sie_block->tecmc >> 31) & 0x1)
+#define old_as_is_home(vcpu) !(vcpu->arch.sie_block->tecmc & 0xffff)
+
 void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu)
 {
+       int new_as;
+
        if (debug_exit_required(vcpu))
                vcpu->guest_debug |= KVM_GUESTDBG_EXIT_PENDING;
 
        filter_guest_per_event(vcpu);
+
+       /*
+        * Only RP, SAC, SACF, PT, PTI, PR, PC instructions can trigger
+        * a space-switch event. PER events enforce space-switch events
+        * for these instructions. So if no PER event for the guest is left,
+        * we might have to filter the space-switch element out, too.
+        */
+       if (vcpu->arch.sie_block->iprcc == PGM_SPACE_SWITCH) {
+               vcpu->arch.sie_block->iprcc = 0;
+               new_as = psw_bits(vcpu->arch.sie_block->gpsw).as;
+
+               /*
+                * If the AS changed from / to home, we had RP, SAC or SACF
+                * instruction. Check primary and home space-switch-event
+                * controls. (theoretically home -> home produced no event)
+                */
+               if (((new_as == PSW_AS_HOME) ^ old_as_is_home(vcpu)) &&
+                    (pssec(vcpu) || hssec(vcpu)))
+                       vcpu->arch.sie_block->iprcc = PGM_SPACE_SWITCH;
+
+               /*
+                * PT, PTI, PR, PC instruction operate on primary AS only. Check
+                * if the primary-space-switch-event control was or got set.
+                */
+               if (new_as == PSW_AS_PRIMARY && !old_as_is_home(vcpu) &&
+                   (pssec(vcpu) || old_ssec(vcpu)))
+                       vcpu->arch.sie_block->iprcc = PGM_SPACE_SWITCH;
+       }
 }