diff options
Diffstat (limited to 'arch/s390/kvm/interrupt.c')
-rw-r--r-- | arch/s390/kvm/interrupt.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 52cdf20906ab..b3b4748485ee 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -41,6 +41,11 @@ static int psw_ioint_disabled(struct kvm_vcpu *vcpu) | |||
41 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO); | 41 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO); |
42 | } | 42 | } |
43 | 43 | ||
44 | static int psw_mchk_disabled(struct kvm_vcpu *vcpu) | ||
45 | { | ||
46 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_MCHECK); | ||
47 | } | ||
48 | |||
44 | static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) | 49 | static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) |
45 | { | 50 | { |
46 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || | 51 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || |
@@ -82,6 +87,12 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, | |||
82 | case KVM_S390_SIGP_SET_PREFIX: | 87 | case KVM_S390_SIGP_SET_PREFIX: |
83 | case KVM_S390_RESTART: | 88 | case KVM_S390_RESTART: |
84 | return 1; | 89 | return 1; |
90 | case KVM_S390_MCHK: | ||
91 | if (psw_mchk_disabled(vcpu)) | ||
92 | return 0; | ||
93 | if (vcpu->arch.sie_block->gcr[14] & inti->mchk.cr14) | ||
94 | return 1; | ||
95 | return 0; | ||
85 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | 96 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
86 | if (psw_ioint_disabled(vcpu)) | 97 | if (psw_ioint_disabled(vcpu)) |
87 | return 0; | 98 | return 0; |
@@ -116,6 +127,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) | |||
116 | CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, | 127 | CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, |
117 | &vcpu->arch.sie_block->cpuflags); | 128 | &vcpu->arch.sie_block->cpuflags); |
118 | vcpu->arch.sie_block->lctl = 0x0000; | 129 | vcpu->arch.sie_block->lctl = 0x0000; |
130 | vcpu->arch.sie_block->ictl &= ~ICTL_LPSW; | ||
119 | } | 131 | } |
120 | 132 | ||
121 | static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) | 133 | static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) |
@@ -139,6 +151,12 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, | |||
139 | case KVM_S390_SIGP_STOP: | 151 | case KVM_S390_SIGP_STOP: |
140 | __set_cpuflag(vcpu, CPUSTAT_STOP_INT); | 152 | __set_cpuflag(vcpu, CPUSTAT_STOP_INT); |
141 | break; | 153 | break; |
154 | case KVM_S390_MCHK: | ||
155 | if (psw_mchk_disabled(vcpu)) | ||
156 | vcpu->arch.sie_block->ictl |= ICTL_LPSW; | ||
157 | else | ||
158 | vcpu->arch.sie_block->lctl |= LCTL_CR14; | ||
159 | break; | ||
142 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | 160 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
143 | if (psw_ioint_disabled(vcpu)) | 161 | if (psw_ioint_disabled(vcpu)) |
144 | __set_cpuflag(vcpu, CPUSTAT_IO_INT); | 162 | __set_cpuflag(vcpu, CPUSTAT_IO_INT); |
@@ -326,6 +344,32 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | |||
326 | exception = 1; | 344 | exception = 1; |
327 | break; | 345 | break; |
328 | 346 | ||
347 | case KVM_S390_MCHK: | ||
348 | VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx", | ||
349 | inti->mchk.mcic); | ||
350 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, | ||
351 | inti->mchk.cr14, | ||
352 | inti->mchk.mcic); | ||
353 | rc = kvm_s390_vcpu_store_status(vcpu, | ||
354 | KVM_S390_STORE_STATUS_PREFIXED); | ||
355 | if (rc == -EFAULT) | ||
356 | exception = 1; | ||
357 | |||
358 | rc = put_guest_u64(vcpu, __LC_MCCK_CODE, inti->mchk.mcic); | ||
359 | if (rc == -EFAULT) | ||
360 | exception = 1; | ||
361 | |||
362 | rc = copy_to_guest(vcpu, __LC_MCK_OLD_PSW, | ||
363 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
364 | if (rc == -EFAULT) | ||
365 | exception = 1; | ||
366 | |||
367 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
368 | __LC_MCK_NEW_PSW, sizeof(psw_t)); | ||
369 | if (rc == -EFAULT) | ||
370 | exception = 1; | ||
371 | break; | ||
372 | |||
329 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | 373 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
330 | { | 374 | { |
331 | __u32 param0 = ((__u32)inti->io.subchannel_id << 16) | | 375 | __u32 param0 = ((__u32)inti->io.subchannel_id << 16) | |
@@ -588,6 +632,61 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) | |||
588 | } | 632 | } |
589 | } | 633 | } |
590 | 634 | ||
635 | void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu) | ||
636 | { | ||
637 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
638 | struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; | ||
639 | struct kvm_s390_interrupt_info *n, *inti = NULL; | ||
640 | int deliver; | ||
641 | |||
642 | __reset_intercept_indicators(vcpu); | ||
643 | if (atomic_read(&li->active)) { | ||
644 | do { | ||
645 | deliver = 0; | ||
646 | spin_lock_bh(&li->lock); | ||
647 | list_for_each_entry_safe(inti, n, &li->list, list) { | ||
648 | if ((inti->type == KVM_S390_MCHK) && | ||
649 | __interrupt_is_deliverable(vcpu, inti)) { | ||
650 | list_del(&inti->list); | ||
651 | deliver = 1; | ||
652 | break; | ||
653 | } | ||
654 | __set_intercept_indicator(vcpu, inti); | ||
655 | } | ||
656 | if (list_empty(&li->list)) | ||
657 | atomic_set(&li->active, 0); | ||
658 | spin_unlock_bh(&li->lock); | ||
659 | if (deliver) { | ||
660 | __do_deliver_interrupt(vcpu, inti); | ||
661 | kfree(inti); | ||
662 | } | ||
663 | } while (deliver); | ||
664 | } | ||
665 | |||
666 | if (atomic_read(&fi->active)) { | ||
667 | do { | ||
668 | deliver = 0; | ||
669 | spin_lock(&fi->lock); | ||
670 | list_for_each_entry_safe(inti, n, &fi->list, list) { | ||
671 | if ((inti->type == KVM_S390_MCHK) && | ||
672 | __interrupt_is_deliverable(vcpu, inti)) { | ||
673 | list_del(&inti->list); | ||
674 | deliver = 1; | ||
675 | break; | ||
676 | } | ||
677 | __set_intercept_indicator(vcpu, inti); | ||
678 | } | ||
679 | if (list_empty(&fi->list)) | ||
680 | atomic_set(&fi->active, 0); | ||
681 | spin_unlock(&fi->lock); | ||
682 | if (deliver) { | ||
683 | __do_deliver_interrupt(vcpu, inti); | ||
684 | kfree(inti); | ||
685 | } | ||
686 | } while (deliver); | ||
687 | } | ||
688 | } | ||
689 | |||
591 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) | 690 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) |
592 | { | 691 | { |
593 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | 692 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
@@ -641,6 +740,13 @@ int kvm_s390_inject_vm(struct kvm *kvm, | |||
641 | case KVM_S390_INT_EMERGENCY: | 740 | case KVM_S390_INT_EMERGENCY: |
642 | kfree(inti); | 741 | kfree(inti); |
643 | return -EINVAL; | 742 | return -EINVAL; |
743 | case KVM_S390_MCHK: | ||
744 | VM_EVENT(kvm, 5, "inject: machine check parm64:%llx", | ||
745 | s390int->parm64); | ||
746 | inti->type = s390int->type; | ||
747 | inti->mchk.cr14 = s390int->parm; /* upper bits are not used */ | ||
748 | inti->mchk.mcic = s390int->parm64; | ||
749 | break; | ||
644 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | 750 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
645 | if (s390int->type & IOINT_AI_MASK) | 751 | if (s390int->type & IOINT_AI_MASK) |
646 | VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)"); | 752 | VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)"); |
@@ -749,6 +855,12 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | |||
749 | inti->type = s390int->type; | 855 | inti->type = s390int->type; |
750 | inti->emerg.code = s390int->parm; | 856 | inti->emerg.code = s390int->parm; |
751 | break; | 857 | break; |
858 | case KVM_S390_MCHK: | ||
859 | VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx", | ||
860 | s390int->parm64); | ||
861 | inti->type = s390int->type; | ||
862 | inti->mchk.mcic = s390int->parm64; | ||
863 | break; | ||
752 | case KVM_S390_INT_VIRTIO: | 864 | case KVM_S390_INT_VIRTIO: |
753 | case KVM_S390_INT_SERVICE: | 865 | case KVM_S390_INT_SERVICE: |
754 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | 866 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |