diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2012-12-20 09:32:09 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2013-01-07 16:53:41 -0500 |
commit | 48a3e950f4cee6a345ffbe9baf599f1e9a54c479 (patch) | |
tree | 3e60015a025df89b28df12c6470babbfb566e766 /arch/s390/kvm | |
parent | d8346b7d9bab37e6cc712ff1622c65ff98bdfef8 (diff) |
KVM: s390: Add support for machine checks.
Add support for injecting machine checks (only repressible
conditions for now).
This is a bit more involved than I/O interrupts, for these reasons:
- Machine checks come in both floating and cpu varieties.
- We don't have a bit for machine checks enabling, but have to use
a roundabout approach with trapping PSW changing instructions and
watching for opened machine checks.
Reviewed-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r-- | arch/s390/kvm/intercept.c | 2 | ||||
-rw-r--r-- | arch/s390/kvm/interrupt.c | 112 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 3 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 135 | ||||
-rw-r--r-- | arch/s390/kvm/trace-s390.h | 6 |
5 files changed, 255 insertions, 3 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index df6c0ad085aa..950c13ecaf60 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -97,10 +97,12 @@ static int handle_lctl(struct kvm_vcpu *vcpu) | |||
97 | 97 | ||
98 | static const intercept_handler_t instruction_handlers[256] = { | 98 | static const intercept_handler_t instruction_handlers[256] = { |
99 | [0x01] = kvm_s390_handle_01, | 99 | [0x01] = kvm_s390_handle_01, |
100 | [0x82] = kvm_s390_handle_lpsw, | ||
100 | [0x83] = kvm_s390_handle_diag, | 101 | [0x83] = kvm_s390_handle_diag, |
101 | [0xae] = kvm_s390_handle_sigp, | 102 | [0xae] = kvm_s390_handle_sigp, |
102 | [0xb2] = kvm_s390_handle_b2, | 103 | [0xb2] = kvm_s390_handle_b2, |
103 | [0xb7] = handle_lctl, | 104 | [0xb7] = handle_lctl, |
105 | [0xb9] = kvm_s390_handle_b9, | ||
104 | [0xe5] = kvm_s390_handle_e5, | 106 | [0xe5] = kvm_s390_handle_e5, |
105 | [0xeb] = handle_lctlg, | 107 | [0xeb] = handle_lctlg, |
106 | }; | 108 | }; |
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: |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index dccc0242b7ca..1f7cc6ccf102 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -106,6 +106,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); | |||
106 | enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer); | 106 | enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer); |
107 | void kvm_s390_tasklet(unsigned long parm); | 107 | void kvm_s390_tasklet(unsigned long parm); |
108 | void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); | 108 | void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); |
109 | void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu); | ||
109 | int kvm_s390_inject_vm(struct kvm *kvm, | 110 | int kvm_s390_inject_vm(struct kvm *kvm, |
110 | struct kvm_s390_interrupt *s390int); | 111 | struct kvm_s390_interrupt *s390int); |
111 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | 112 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, |
@@ -117,6 +118,8 @@ int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); | |||
117 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); | 118 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); |
118 | int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); | 119 | int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); |
119 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); | 120 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); |
121 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); | ||
122 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); | ||
120 | 123 | ||
121 | /* implemented in sigp.c */ | 124 | /* implemented in sigp.c */ |
122 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); | 125 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index d715842f56ca..d3cbcd3c9ada 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <asm/debug.h> | 18 | #include <asm/debug.h> |
19 | #include <asm/ebcdic.h> | 19 | #include <asm/ebcdic.h> |
20 | #include <asm/sysinfo.h> | 20 | #include <asm/sysinfo.h> |
21 | #include <asm/ptrace.h> | ||
22 | #include <asm/compat.h> | ||
21 | #include "gaccess.h" | 23 | #include "gaccess.h" |
22 | #include "kvm-s390.h" | 24 | #include "kvm-s390.h" |
23 | #include "trace.h" | 25 | #include "trace.h" |
@@ -166,6 +168,99 @@ static int handle_stfl(struct kvm_vcpu *vcpu) | |||
166 | return 0; | 168 | return 0; |
167 | } | 169 | } |
168 | 170 | ||
171 | static void handle_new_psw(struct kvm_vcpu *vcpu) | ||
172 | { | ||
173 | /* Check whether the new psw is enabled for machine checks. */ | ||
174 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_MCHECK) | ||
175 | kvm_s390_deliver_pending_machine_checks(vcpu); | ||
176 | } | ||
177 | |||
178 | #define PSW_MASK_ADDR_MODE (PSW_MASK_EA | PSW_MASK_BA) | ||
179 | #define PSW_MASK_UNASSIGNED 0xb80800fe7fffffffUL | ||
180 | #define PSW_ADDR_24 0x00000000000fffffUL | ||
181 | #define PSW_ADDR_31 0x000000007fffffffUL | ||
182 | |||
183 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu) | ||
184 | { | ||
185 | u64 addr; | ||
186 | psw_compat_t new_psw; | ||
187 | |||
188 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
189 | return kvm_s390_inject_program_int(vcpu, | ||
190 | PGM_PRIVILEGED_OPERATION); | ||
191 | |||
192 | addr = kvm_s390_get_base_disp_s(vcpu); | ||
193 | |||
194 | if (addr & 7) { | ||
195 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) { | ||
200 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | if (!(new_psw.mask & PSW32_MASK_BASE)) { | ||
205 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
206 | goto out; | ||
207 | } | ||
208 | |||
209 | vcpu->arch.sie_block->gpsw.mask = | ||
210 | (new_psw.mask & ~PSW32_MASK_BASE) << 32; | ||
211 | vcpu->arch.sie_block->gpsw.addr = new_psw.addr; | ||
212 | |||
213 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) || | ||
214 | (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) && | ||
215 | (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) || | ||
216 | ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == | ||
217 | PSW_MASK_EA)) { | ||
218 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
219 | goto out; | ||
220 | } | ||
221 | |||
222 | handle_new_psw(vcpu); | ||
223 | out: | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int handle_lpswe(struct kvm_vcpu *vcpu) | ||
228 | { | ||
229 | u64 addr; | ||
230 | psw_t new_psw; | ||
231 | |||
232 | addr = kvm_s390_get_base_disp_s(vcpu); | ||
233 | |||
234 | if (addr & 7) { | ||
235 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
236 | goto out; | ||
237 | } | ||
238 | |||
239 | if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) { | ||
240 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
241 | goto out; | ||
242 | } | ||
243 | |||
244 | vcpu->arch.sie_block->gpsw.mask = new_psw.mask; | ||
245 | vcpu->arch.sie_block->gpsw.addr = new_psw.addr; | ||
246 | |||
247 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) || | ||
248 | (((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == | ||
249 | PSW_MASK_BA) && | ||
250 | (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_31)) || | ||
251 | (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) && | ||
252 | (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) || | ||
253 | ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == | ||
254 | PSW_MASK_EA)) { | ||
255 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
256 | goto out; | ||
257 | } | ||
258 | |||
259 | handle_new_psw(vcpu); | ||
260 | out: | ||
261 | return 0; | ||
262 | } | ||
263 | |||
169 | static int handle_stidp(struct kvm_vcpu *vcpu) | 264 | static int handle_stidp(struct kvm_vcpu *vcpu) |
170 | { | 265 | { |
171 | u64 operand2; | 266 | u64 operand2; |
@@ -292,6 +387,7 @@ static const intercept_handler_t priv_handlers[256] = { | |||
292 | [0x5f] = handle_chsc, | 387 | [0x5f] = handle_chsc, |
293 | [0x7d] = handle_stsi, | 388 | [0x7d] = handle_stsi, |
294 | [0xb1] = handle_stfl, | 389 | [0xb1] = handle_stfl, |
390 | [0xb2] = handle_lpswe, | ||
295 | }; | 391 | }; |
296 | 392 | ||
297 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) | 393 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) |
@@ -316,6 +412,45 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) | |||
316 | return -EOPNOTSUPP; | 412 | return -EOPNOTSUPP; |
317 | } | 413 | } |
318 | 414 | ||
415 | static int handle_epsw(struct kvm_vcpu *vcpu) | ||
416 | { | ||
417 | int reg1, reg2; | ||
418 | |||
419 | reg1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 24; | ||
420 | reg2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16; | ||
421 | |||
422 | /* This basically extracts the mask half of the psw. */ | ||
423 | vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000; | ||
424 | vcpu->run->s.regs.gprs[reg1] |= vcpu->arch.sie_block->gpsw.mask >> 32; | ||
425 | if (reg2) { | ||
426 | vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000; | ||
427 | vcpu->run->s.regs.gprs[reg2] |= | ||
428 | vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffff; | ||
429 | } | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static const intercept_handler_t b9_handlers[256] = { | ||
434 | [0x8d] = handle_epsw, | ||
435 | }; | ||
436 | |||
437 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) | ||
438 | { | ||
439 | intercept_handler_t handler; | ||
440 | |||
441 | /* This is handled just as for the B2 instructions. */ | ||
442 | handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; | ||
443 | if (handler) { | ||
444 | if ((handler != handle_epsw) && | ||
445 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)) | ||
446 | return kvm_s390_inject_program_int(vcpu, | ||
447 | PGM_PRIVILEGED_OPERATION); | ||
448 | else | ||
449 | return handler(vcpu); | ||
450 | } | ||
451 | return -EOPNOTSUPP; | ||
452 | } | ||
453 | |||
319 | static int handle_tprot(struct kvm_vcpu *vcpu) | 454 | static int handle_tprot(struct kvm_vcpu *vcpu) |
320 | { | 455 | { |
321 | u64 address1, address2; | 456 | u64 address1, address2; |
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h index 90fdf85b5ff7..95fbc1ab88dc 100644 --- a/arch/s390/kvm/trace-s390.h +++ b/arch/s390/kvm/trace-s390.h | |||
@@ -141,13 +141,13 @@ TRACE_EVENT(kvm_s390_inject_vcpu, | |||
141 | * Trace point for the actual delivery of interrupts. | 141 | * Trace point for the actual delivery of interrupts. |
142 | */ | 142 | */ |
143 | TRACE_EVENT(kvm_s390_deliver_interrupt, | 143 | TRACE_EVENT(kvm_s390_deliver_interrupt, |
144 | TP_PROTO(unsigned int id, __u64 type, __u32 data0, __u64 data1), | 144 | TP_PROTO(unsigned int id, __u64 type, __u64 data0, __u64 data1), |
145 | TP_ARGS(id, type, data0, data1), | 145 | TP_ARGS(id, type, data0, data1), |
146 | 146 | ||
147 | TP_STRUCT__entry( | 147 | TP_STRUCT__entry( |
148 | __field(int, id) | 148 | __field(int, id) |
149 | __field(__u32, inttype) | 149 | __field(__u32, inttype) |
150 | __field(__u32, data0) | 150 | __field(__u64, data0) |
151 | __field(__u64, data1) | 151 | __field(__u64, data1) |
152 | ), | 152 | ), |
153 | 153 | ||
@@ -159,7 +159,7 @@ TRACE_EVENT(kvm_s390_deliver_interrupt, | |||
159 | ), | 159 | ), |
160 | 160 | ||
161 | TP_printk("deliver interrupt (vcpu %d): type:%x (%s) " \ | 161 | TP_printk("deliver interrupt (vcpu %d): type:%x (%s) " \ |
162 | "data:%08x %016llx", | 162 | "data:%08llx %016llx", |
163 | __entry->id, __entry->inttype, | 163 | __entry->id, __entry->inttype, |
164 | __print_symbolic(__entry->inttype, kvm_s390_int_type), | 164 | __print_symbolic(__entry->inttype, kvm_s390_int_type), |
165 | __entry->data0, __entry->data1) | 165 | __entry->data0, __entry->data1) |