]> git.karo-electronics.de Git - linux-beck.git/commitdiff
KVM: s390: inject PER i-fetch events on applicable icpts
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Tue, 24 May 2016 10:10:27 +0000 (12:10 +0200)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Tue, 5 Jul 2016 10:02:56 +0000 (12:02 +0200)
In case we have to emuluate an instruction or part of it (instruction,
partial instruction, operation exception), we have to inject a PER
instruction-fetching event for that instruction, if hardware told us to do
so.

In case we retry an instruction, we must not inject the PER event.

Please note that we don't filter the events properly yet, so guest
debugging will be visible for the guest.

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

index 1e0849e209650dbe8e5de156a6afa1d3bdf45bf3..31a05330d11c77fc0c34cd30ea54bc2075a2c3d9 100644 (file)
@@ -439,6 +439,23 @@ exit_required:
 #define guest_per_enabled(vcpu) \
                             (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER)
 
+int kvm_s390_handle_per_ifetch_icpt(struct kvm_vcpu *vcpu)
+{
+       const u8 ilen = kvm_s390_get_ilen(vcpu);
+       struct kvm_s390_pgm_info pgm_info = {
+               .code = PGM_PER,
+               .per_code = PER_EVENT_IFETCH >> 24,
+               .per_address = __rewind_psw(vcpu->arch.sie_block->gpsw, ilen),
+       };
+
+       /*
+        * The PSW points to the next instruction, therefore the intercepted
+        * instruction generated a PER i-fetch event. PER address therefore
+        * points at the previous PSW address (could be an EXECUTE function).
+        */
+       return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
+}
+
 static void filter_guest_per_event(struct kvm_vcpu *vcpu)
 {
        u32 perc = vcpu->arch.sie_block->perc << 24;
index 9359f65c8634ba3f6924b42ac863618e59be6e9f..850be47c4cc93fa4b7033a096b986a1670cb3cdd 100644 (file)
@@ -364,6 +364,8 @@ static int handle_operexc(struct kvm_vcpu *vcpu)
 
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
 {
+       int rc, per_rc = 0;
+
        if (kvm_is_ucontrol(vcpu->kvm))
                return -EOPNOTSUPP;
 
@@ -372,7 +374,8 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
        case 0x18:
                return handle_noop(vcpu);
        case 0x04:
-               return handle_instruction(vcpu);
+               rc = handle_instruction(vcpu);
+               break;
        case 0x08:
                return handle_prog(vcpu);
        case 0x14:
@@ -384,10 +387,18 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
        case 0x28:
                return handle_stop(vcpu);
        case 0x2c:
-               return handle_operexc(vcpu);
+               rc = handle_operexc(vcpu);
+               break;
        case 0x38:
-               return handle_partial_execution(vcpu);
+               rc = handle_partial_execution(vcpu);
+               break;
        default:
                return -EOPNOTSUPP;
        }
+
+       /* process PER, also if the instrution is processed in user space */
+       if (vcpu->arch.sie_block->icptstatus & 0x02 &&
+           (!rc || rc == -EOPNOTSUPP))
+               per_rc = kvm_s390_handle_per_ifetch_icpt(vcpu);
+       return per_rc ? per_rc : rc;
 }
index 031f451bb2cf79a2550b14eb6bd2701a0e29d765..b8432862a81715761fbe274071d0988021b61a54 100644 (file)
@@ -238,6 +238,8 @@ static inline void kvm_s390_forward_psw(struct kvm_vcpu *vcpu, int ilen)
 }
 static inline void kvm_s390_retry_instr(struct kvm_vcpu *vcpu)
 {
+       /* don't inject PER events if we re-execute the instruction */
+       vcpu->arch.sie_block->icptstatus &= ~0x02;
        kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu));
 }
 
@@ -377,6 +379,7 @@ int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu,
                            struct kvm_guest_debug *dbg);
 void kvm_s390_clear_bp_data(struct kvm_vcpu *vcpu);
 void kvm_s390_prepare_debug_exit(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_per_ifetch_icpt(struct kvm_vcpu *vcpu);
 void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu);
 
 /* support for Basic/Extended SCA handling */