aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/intercept.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kvm/intercept.c')
-rw-r--r--arch/s390/kvm/intercept.c41
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
69static int handle_stop(struct kvm_vcpu *vcpu) 69static 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, &reg1, &reg2); 318 kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
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;