KVM: s390: filter space-switch events when PER is enforced
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Tue, 23 Jun 2015 20:49:36 +0000 (22:49 +0200)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Wed, 29 Jul 2015 08:36:22 +0000 (10:36 +0200)
When guest debugging is active, space-switch events might be enforced
by PER. While the PER events are correctly filtered out,
space-switch-events could be forwarded to the guest, although from a
guest point of view, they should not have been reported.

Therefore we have to filter out space-switch events being concurrently
reported with a PER event, if the PER event got filtered out. To do so,
we theoretically have to know which instruction was responsible for the
event. As the applicable instructions modify the PSW address, the
address space set in the PSW and even the address space in cr1, we
can't figure out the instruction that way.

For this reason, we have to rely on the information about the old and
new address space, in order to guess the responsible instruction type
and do appropriate checks for space-switch events.

Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/kvm/guestdbg.c

index e97b3455d7e6bfbb7b12c606a5224c5efeba37d4..47518a324d752286d4b0cb80784c43c316f31c45 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;
+       }
 }