diff options
Diffstat (limited to 'arch/s390/kvm/intercept.c')
-rw-r--r-- | arch/s390/kvm/intercept.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 81c77ab8102e..bebd2157edd0 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -68,18 +68,27 @@ static int handle_noop(struct kvm_vcpu *vcpu) | |||
68 | 68 | ||
69 | static int handle_stop(struct kvm_vcpu *vcpu) | 69 | static int handle_stop(struct kvm_vcpu *vcpu) |
70 | { | 70 | { |
71 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
71 | int rc = 0; | 72 | int rc = 0; |
72 | unsigned int action_bits; | 73 | uint8_t flags, stop_pending; |
73 | 74 | ||
74 | vcpu->stat.exit_stop_request++; | 75 | vcpu->stat.exit_stop_request++; |
75 | trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits); | ||
76 | 76 | ||
77 | action_bits = vcpu->arch.local_int.action_bits; | 77 | /* delay the stop if any non-stop irq is pending */ |
78 | if (kvm_s390_vcpu_has_irq(vcpu, 1)) | ||
79 | return 0; | ||
80 | |||
81 | /* avoid races with the injection/SIGP STOP code */ | ||
82 | spin_lock(&li->lock); | ||
83 | flags = li->irq.stop.flags; | ||
84 | stop_pending = kvm_s390_is_stop_irq_pending(vcpu); | ||
85 | spin_unlock(&li->lock); | ||
78 | 86 | ||
79 | if (!(action_bits & ACTION_STOP_ON_STOP)) | 87 | trace_kvm_s390_stop_request(stop_pending, flags); |
88 | if (!stop_pending) | ||
80 | return 0; | 89 | return 0; |
81 | 90 | ||
82 | if (action_bits & ACTION_STORE_ON_STOP) { | 91 | if (flags & KVM_S390_STOP_FLAG_STORE_STATUS) { |
83 | rc = kvm_s390_vcpu_store_status(vcpu, | 92 | rc = kvm_s390_vcpu_store_status(vcpu, |
84 | KVM_S390_STORE_STATUS_NOADDR); | 93 | KVM_S390_STORE_STATUS_NOADDR); |
85 | if (rc) | 94 | if (rc) |
@@ -279,11 +288,13 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu) | |||
279 | irq.type = KVM_S390_INT_CPU_TIMER; | 288 | irq.type = KVM_S390_INT_CPU_TIMER; |
280 | break; | 289 | break; |
281 | case EXT_IRQ_EXTERNAL_CALL: | 290 | case EXT_IRQ_EXTERNAL_CALL: |
282 | if (kvm_s390_si_ext_call_pending(vcpu)) | ||
283 | return 0; | ||
284 | irq.type = KVM_S390_INT_EXTERNAL_CALL; | 291 | irq.type = KVM_S390_INT_EXTERNAL_CALL; |
285 | irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr; | 292 | irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr; |
286 | break; | 293 | rc = kvm_s390_inject_vcpu(vcpu, &irq); |
294 | /* ignore if another external call is already pending */ | ||
295 | if (rc == -EBUSY) | ||
296 | return 0; | ||
297 | return rc; | ||
287 | default: | 298 | default: |
288 | return -EOPNOTSUPP; | 299 | return -EOPNOTSUPP; |
289 | } | 300 | } |
@@ -307,17 +318,19 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu) | |||
307 | kvm_s390_get_regs_rre(vcpu, ®1, ®2); | 318 | kvm_s390_get_regs_rre(vcpu, ®1, ®2); |
308 | 319 | ||
309 | /* Make sure that the source is paged-in */ | 320 | /* Make sure that the source is paged-in */ |
310 | srcaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg2]); | 321 | rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg2], |
311 | if (kvm_is_error_gpa(vcpu->kvm, srcaddr)) | 322 | &srcaddr, 0); |
312 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | 323 | if (rc) |
324 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
313 | rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0); | 325 | rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0); |
314 | if (rc != 0) | 326 | if (rc != 0) |
315 | return rc; | 327 | return rc; |
316 | 328 | ||
317 | /* Make sure that the destination is paged-in */ | 329 | /* Make sure that the destination is paged-in */ |
318 | dstaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg1]); | 330 | rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg1], |
319 | if (kvm_is_error_gpa(vcpu->kvm, dstaddr)) | 331 | &dstaddr, 1); |
320 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | 332 | if (rc) |
333 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
321 | rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1); | 334 | rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1); |
322 | if (rc != 0) | 335 | if (rc != 0) |
323 | return rc; | 336 | return rc; |